import { BaseUserMeta, Client, RoomSubscriptionSettings, Json, JsonObject, LsonObject, LiveObject, User, Room, Status, BroadcastOptions, OthersEvent, LostConnectionEvent, History, BaseMetadata as BaseMetadata$1, ClientOptions, CommentData as CommentData$1, ThreadData as ThreadData$1, FeedCreateMetadata as FeedCreateMetadata$1, FeedUpdateMetadata as FeedUpdateMetadata$1 } from '@liveblocks/client'; import * as _liveblocks_core from '@liveblocks/core'; import { OpaqueClient, OpaqueRoom, Relax, AiAssistantContentPart, AiKnowledgeSource, AiOpaqueToolDefinition, BaseMetadata, QueryMetadata, AsyncLoading, AsyncError, Resolve, AsyncSuccess, ThreadData, InboxNotificationData, AsyncResult, HistoryVersion, NotificationSettings, AiChat, WithNavigation, AiChatMessage, UrlMetadata, Feed, FeedMessage, CommentBody, CommentAttachment, PartialUnless, Patchable, GroupData, RoomEventMessage, CommentData, Client as Client$1, DRI, DGI, LiveblocksError, SyncStatus, ToJson, FeedFetchMetadataFilter, FeedCreateMetadata, FeedUpdateMetadata, SearchCommentsResult, PartialNotificationSettings, AiUserMessage, WithRequired, AiChatsQuery, MessageId, MutableSignal, ThreadDataWithDeleteInfo, ThreadDeleteInfo, SubscriptionKey, SubscriptionData, ISignal, InboxNotificationDeleteInfo, CommentUserReaction, RoomSubscriptionSettings as RoomSubscriptionSettings$1, DerivedSignal, SubscriptionDeleteInfo, Permission, BaseUserMeta as BaseUserMeta$1, DistributiveOmit, DefaultMap, DU, DTM, DCM, MentionData, TextEditorType, IYjsProvider, DP, DS, DE, DFM, DFMD } from '@liveblocks/core'; import { Context, ReactNode, ComponentType, PropsWithChildren } from 'react'; import * as react_jsx_runtime from 'react/jsx-runtime'; /** * Raw access to the React context where the LiveblocksProvider stores the * current client. Exposed for advanced use cases only. * * @private This is a private/advanced API. Do not rely on it. */ declare const ClientContext: Context; /** * @private This is an internal API. */ declare function useClientOrNull(): Client | null; /** * Obtains a reference to the current Liveblocks client. */ declare function useClient(): Client; /** * Raw access to the React context where the RoomProvider stores the current * room. Exposed for advanced use cases only. * * @private This is a private/advanced API. Do not rely on it. * * This context is exported publicly as `import { RoomContext } from "@liveblocks/react"`, * not `GlobalRoomContext`. */ declare const GlobalRoomContext: Context; type RegisterAiKnowledgeProps = AiKnowledgeSource & { /** * An optional unique key for this knowledge source. If multiple components * register knowledge under the same key, the last one to mount takes * precedence. */ id?: string; /** * When provided, the knowledge source will only be available for this chatId. * If not provided, this knowledge source will be available globally. */ chatId?: string; }; type RegisterAiToolProps = { name: string; tool: AiOpaqueToolDefinition; /** * When provided, the tool will only be available for this chatId. If not * provided, this tool will be available globally. */ chatId?: string; /** * Whether this tool should be enabled. When set to `false`, the tool will * not be made available to the AI copilot for any new/future chat messages, * but will still allow existing tool invocations to be rendered that are * part of the historic chat record. Defaults to true. */ enabled?: boolean; }; /** * Simplified status for the requested chat. * This hook offers a convenient way to update the UI while an AI chat * generation is in progress. */ type AiChatStatus = Relax<{ status: "disconnected"; } | { status: "loading"; } | { status: "idle"; } | { status: "generating"; } | { status: "generating"; partType: Exclude; } | { status: "generating"; partType: "tool-invocation"; toolName: string; }>; type UiChatMessage = WithNavigation; type UseSyncStatusOptions = { /** * When setting smooth, the hook will not update immediately as status * changes. This is because in typical applications, these states can change * quickly between synchronizing and synchronized. If you use this hook to * build a "Saving changes..." style UI, prefer setting `smooth: true`. */ smooth?: boolean; }; type UseSendAiMessageOptions = { /** * The ID of the copilot to use to send the message. */ copilotId?: string; /** * Stream the response as it is being generated. Defaults to true. */ stream?: boolean; /** * The maximum timeout for the answer to be generated. */ timeout?: number; }; type SendAiMessageOptions = UseSendAiMessageOptions & { /** * The ID of the chat to send the message to. */ chatId?: string; /** * The text of the message to send. */ text: string; }; type CreateAiChatOptions = { id: string; title?: string; metadata?: Record; }; type UseAiChatsOptions = { /** * The query (including metadata) to filter the chats by. If provided, only chats * that match the query will be returned. If not provided, all chats will be returned. */ query?: AiChatsQuery; }; type ThreadsQuery = { /** * Whether to only return threads marked as resolved or unresolved. If not provided, * all threads will be returned. */ resolved?: boolean; /** * Whether to only return threads that the user is subscribed to or not. If not provided, * all threads will be returned. */ subscribed?: boolean; /** * The metadata to filter the threads by. If provided, only threads with metadata that matches * the provided metadata will be returned. If not provided, all threads will be returned. */ metadata?: Partial>; }; type UseUserThreadsOptions = { /** * The query (including metadata) to filter the threads by. If provided, only threads * that match the query will be returned. If not provided, all threads will be returned. */ query?: ThreadsQuery; }; type UseThreadsOptions = { /** * The query (including metadata) to filter the threads by. If provided, only threads * that match the query will be returned. If not provided, all threads will be returned. */ query?: ThreadsQuery; /** * Whether to scroll to a comment on load based on the URL hash. Defaults to `true`. * * @example * Given the URL `https://example.com/my-room#cm_xxx`, the `cm_xxx` comment will be * scrolled to on load if it exists in the page. */ scrollOnLoad?: boolean; }; type SearchCommentsQuery = { /** * (Optional) Metadata to filter the threads by. */ threadMetadata?: Partial>; /** * (Optional) Whether to only return comments from threads marked as resolved or unresolved. */ threadResolved?: boolean; /** * (Optional) Whether to only return comments that have attachments. */ hasAttachments?: boolean; /** * (Optional) Whether to only return comments that have mentions. */ hasMentions?: boolean; /** * (Required) Text to search within comment content. Uses rich text and vector search for relevance. */ text: string; }; type UseSearchCommentsOptions = { query: SearchCommentsQuery; }; type InboxNotificationsQuery = { /** * Whether to only return inbox notifications for a specific room. */ roomId?: string; /** * Whether to only return inbox notifications for a specific kind. */ kind?: string; }; type UseInboxNotificationsOptions = { /** * The query to filter the inbox notifications by. If provided, only inbox notifications * that match the query will be returned. If not provided, all inbox notifications will be returned. */ query?: InboxNotificationsQuery; }; type UseFeedsOptions = { /** * Optional timestamp filter. Applied to the client-side cache for this hook’s * options: only feeds whose `createdAt` or `updatedAt` is at or after this * timestamp (ms) are included in `feeds`. */ since?: number; /** * Optional metadata filter (`Record`). Applied to the * client-side cache: only feeds whose metadata matches every key/value pair * are included in `feeds`. */ metadata?: FeedFetchMetadataFilter; /** * Page size for each server request when loading or loading more feeds. This * does **not** cap the length of `feeds`—use pagination (`fetchMore`, * `hasFetchedAll`) until you have loaded every page. Different hooks with * different `limit` values still share one cache per room; each hook’s * `feeds` array is filtered and sorted independently. */ limit?: number; }; type UseFeedMessagesOptions = { /** * Optional cursor for pagination. */ cursor?: string; /** * Page size for each server request when loading or loading more messages. * Does **not** cap the length of `messages`—pagination loads additional pages * until `hasFetchedAll` is true. */ limit?: number; }; type UserAsyncResult = AsyncResult; type UserAsyncSuccess = AsyncSuccess; type RoomInfoAsyncResult = AsyncResult; type RoomInfoAsyncSuccess = AsyncSuccess; type GroupInfoAsyncResult = AsyncResult; type GroupInfoAsyncSuccess = AsyncSuccess; type AttachmentUrlAsyncResult = AsyncResult; type AttachmentUrlAsyncSuccess = AsyncSuccess; type GroupAsyncResult = AsyncResult; type CreateThreadOptions = Resolve<{ body: CommentBody; attachments?: CommentAttachment[]; } & PartialUnless & PartialUnless>; type EditThreadMetadataOptions = { threadId: string; metadata: Patchable; }; type CreateCommentOptions = { threadId: string; body: CommentBody; attachments?: CommentAttachment[]; } & PartialUnless; type EditCommentOptions = { threadId: string; commentId: string; body: CommentBody; attachments?: CommentAttachment[]; metadata?: Patchable; }; type EditCommentMetadataOptions = { threadId: string; commentId: string; metadata: Patchable; }; type DeleteCommentOptions = { threadId: string; commentId: string; }; type CommentReactionOptions = { threadId: string; commentId: string; emoji: string; }; type PaginationFields = { hasFetchedAll: boolean; isFetchingMore: boolean; fetchMore: () => void; fetchMoreError?: Error; }; type PagedAsyncSuccess = Resolve & PaginationFields>; type PagedAsyncResult = Relax | AsyncError | PagedAsyncSuccess>; type ThreadsAsyncSuccess = PagedAsyncSuccess[], "threads">; type ThreadsAsyncResult = PagedAsyncResult[], "threads">; type SearchCommentsAsyncResult = AsyncResult, "results">; type InboxNotificationsAsyncSuccess = PagedAsyncSuccess; type InboxNotificationsAsyncResult = PagedAsyncResult; type FeedsAsyncSuccess = PagedAsyncSuccess[], "feeds">; type FeedsAsyncResult = PagedAsyncResult[], "feeds">; type FeedMessagesAsyncSuccess = PagedAsyncSuccess[], "messages">; type FeedMessagesAsyncResult = PagedAsyncResult[], "messages">; type UnreadInboxNotificationsCountAsyncSuccess = AsyncSuccess; type UnreadInboxNotificationsCountAsyncResult = AsyncResult; type NotificationSettingsAsyncResult = AsyncResult; type RoomSubscriptionSettingsAsyncSuccess = AsyncSuccess; type RoomSubscriptionSettingsAsyncResult = AsyncResult; type HistoryVersionDataAsyncResult = AsyncResult; type HistoryVersionsAsyncSuccess = AsyncSuccess; type HistoryVersionsAsyncResult = AsyncResult; type AiChatsAsyncSuccess = PagedAsyncSuccess; type AiChatsAsyncResult = PagedAsyncResult; type AiChatAsyncSuccess = AsyncSuccess; type AiChatAsyncResult = AsyncResult; type AiChatMessagesAsyncSuccess = AsyncSuccess; type AiChatMessagesAsyncResult = AsyncResult; type UrlMetadataAsyncSuccess = AsyncSuccess; type UrlMetadataAsyncResult = AsyncResult; type RoomProviderProps

= Resolve<{ /** * The id of the room you want to connect to */ id: string; children: ReactNode; /** * Whether or not the room should connect to Liveblocks servers * when the RoomProvider is rendered. * * By default equals to `typeof window !== "undefined"`, * meaning the RoomProvider tries to connect to Liveblocks servers * only on the client side. */ autoConnect?: boolean; /** * @deprecated This flag no longer has any effect and will be removed in * a future version. All rooms now use the v2 storage engine by default. */ engine?: 1 | 2; } & PartialUnless P); }> & PartialUnless | ((roomId: string) => S | LiveObject); }>>; /** * For any function type, returns a similar function type, but without the * first argument. */ type OmitFirstArg = F extends (first: any, ...rest: infer A) => infer R ? (...args: A) => R : never; type MutationContext

= { storage: LiveObject; self: User; others: readonly User[]; setMyPresence: (patch: Partial

, options?: { addToHistory: boolean; }) => void; }; type ThreadSubscription = Relax<{ status: "not-subscribed"; subscribe: () => void; unsubscribe: () => void; } | { status: "subscribed"; unreadSince: null; subscribe: () => void; unsubscribe: () => void; } | { status: "subscribed"; unreadSince: Date; subscribe: () => void; unsubscribe: () => void; }>; type SharedContextBundle = { classic: { /** * Obtains a reference to the current Liveblocks client. */ useClient(): Client$1; /** * Returns user info from a given user ID. * * @example * const { user, error, isLoading } = useUser("user-id"); */ useUser(userId: string): UserAsyncResult; /** * Returns room info from a given room ID. * * @example * const { info, error, isLoading } = useRoomInfo("room-id"); */ useRoomInfo(roomId: string): RoomInfoAsyncResult; /** * Returns group info from a given group ID. * * @example * const { info, error, isLoading } = useGroupInfo("group-id"); */ useGroupInfo(groupId: string): GroupInfoAsyncResult; /** * Returns whether the hook is called within a RoomProvider context. * * @example * const isInsideRoom = useIsInsideRoom(); */ useIsInsideRoom(): boolean; /** * useErrorListener is a React hook that allows you to respond to any * Liveblocks error, for example room connection errors, errors * creating/editing/deleting threads, etc. * * @example * useErrorListener(err => { * console.error(err); * }) */ useErrorListener(callback: (err: LiveblocksError) => void): void; /** * Returns the current Liveblocks sync status, and triggers a re-render * whenever it changes. Can be used to render a "Saving..." indicator, or for * preventing that a browser tab can be closed until all changes have been * synchronized with the server. * * @example * const syncStatus = useSyncStatus(); // "synchronizing" | "synchronized" * const syncStatus = useSyncStatus({ smooth: true }); */ useSyncStatus(options?: UseSyncStatusOptions): SyncStatus; /** * Make knowledge about your application state available to any AI used in * a chat or a one-off request. * * For example: * * * * * * By mounting this component, the AI will get access to this knwoledge. * By unmounting this component, the AI will no longer have access to it. * It can choose to use or ignore this knowledge in its responses. */ RegisterAiKnowledge: ComponentType; RegisterAiTool: ComponentType; }; suspense: { /** * Obtains a reference to the current Liveblocks client. */ useClient(): Client$1; /** * Returns user info from a given user ID. * * @example * const { user } = useUser("user-id"); */ useUser(userId: string): UserAsyncSuccess; /** * Returns room info from a given room ID. * * @example * const { info } = useRoomInfo("room-id"); */ useRoomInfo(roomId: string): RoomInfoAsyncSuccess; /** * Returns group info from a given group ID. * * @example * const { info } = useGroupInfo("group-id"); */ useGroupInfo(groupId: string): GroupInfoAsyncSuccess; /** * Returns whether the hook is called within a RoomProvider context. * * @example * const isInsideRoom = useIsInsideRoom(); */ useIsInsideRoom(): boolean; /** * useErrorListener is a React hook that allows you to respond to any * Liveblocks error, for example room connection errors, errors * creating/editing/deleting threads, etc. * * @example * useErrorListener(err => { * console.error(err); * }) */ useErrorListener(callback: (err: LiveblocksError) => void): void; /** * Returns the current Liveblocks sync status, and triggers a re-render * whenever it changes. Can be used to render a "Saving..." indicator, or for * preventing that a browser tab can be closed until all changes have been * synchronized with the server. * * @example * const syncStatus = useSyncStatus(); // "synchronizing" | "synchronized" * const syncStatus = useSyncStatus({ smooth: true }); */ useSyncStatus(options?: UseSyncStatusOptions): SyncStatus; /** * Make knowledge about your application state available to any AI used in * a chat or a one-off request. * * For example: * * * * * * By mounting this component, the AI will get access to this knwoledge. * By unmounting this component, the AI will no longer have access to it. * It can choose to use or ignore this knowledge in its responses. */ RegisterAiKnowledge: ComponentType; RegisterAiTool: ComponentType; }; }; /** * Properties that are the same in RoomContext and RoomContext["suspense"]. */ type RoomContextBundleCommon

= { /** * You normally don't need to directly interact with the RoomContext, but * it can be necessary if you're building an advanced app where you need to * set up a context bridge between two React renderers. */ RoomContext: Context | null>; /** * Makes a Room available in the component hierarchy below. * Joins the room when the component is mounted, and automatically leaves * the room when the component is unmounted. */ RoomProvider(props: RoomProviderProps): JSX.Element; /** * Returns the Room of the nearest RoomProvider above in the React component * tree. */ useRoom(options?: { allowOutsideRoom: false; }): Room; useRoom(options: { allowOutsideRoom: boolean; }): Room | null; /** * Returns the current connection status for the Room, and triggers * a re-render whenever it changes. Can be used to render a status badge. */ useStatus(): Status; /** * Returns a callback that lets you broadcast custom events to other users in the room * * @example * const broadcast = useBroadcastEvent(); * * broadcast({ type: "CUSTOM_EVENT", data: { x: 0, y: 0 } }); */ useBroadcastEvent(): (event: E, options?: BroadcastOptions) => void; /** * Get informed when users enter or leave the room, as an event. * * @example * useOthersListener({ type, user, others }) => { * if (type === 'enter') { * // `user` has joined the room * } else if (type === 'leave') { * // `user` has left the room * } * }) */ useOthersListener(callback: (event: OthersEvent) => void): void; /** * Get informed when reconnecting to the Liveblocks servers is taking * longer than usual. This typically is a sign of a client that has lost * internet connectivity. * * This isn't problematic (because the Liveblocks client is still trying to * reconnect), but it's typically a good idea to inform users about it if * the connection takes too long to recover. * * @example * useLostConnectionListener(event => { * if (event === 'lost') { * toast.warn('Reconnecting to the Liveblocks servers is taking longer than usual...') * } else if (event === 'failed') { * toast.warn('Reconnecting to the Liveblocks servers failed.') * } else if (event === 'restored') { * toast.clear(); * } * }) */ useLostConnectionListener(callback: (event: LostConnectionEvent) => void): void; /** * useEventListener is a React hook that allows you to respond to events broadcast * by other users in the room. * * The `user` argument will indicate which `User` instance sent the message. * This will be equal to one of the others in the room, but it can be `null` * in case this event was broadcasted from the server. * * @example * useEventListener(({ event, user, connectionId }) => { * // ^^^^ Will be Client A * if (event.type === "CUSTOM_EVENT") { * // Do something * } * }); */ useEventListener(callback: (data: RoomEventMessage) => void): void; /** * Returns the room.history */ useHistory(): History; /** * Returns a function that undoes the last operation executed by the current client. * It does not impact operations made by other clients. */ useUndo(): () => void; /** * Returns a function that redoes the last operation executed by the current client. * It does not impact operations made by other clients. */ useRedo(): () => void; /** * Returns whether there are any operations to undo. */ useCanUndo(): boolean; /** * Returns whether there are any operations to redo. */ useCanRedo(): boolean; /** * Returns the mutable (!) Storage root. This hook exists for * backward-compatible reasons. * * @example * const [root] = useStorageRoot(); */ useStorageRoot(): [root: LiveObject | null]; /** * Returns the presence of the current user of the current room, and a function to update it. * It is different from the setState function returned by the useState hook from React. * You don't need to pass the full presence object to update it. * * @example * const [myPresence, updateMyPresence] = useMyPresence(); * updateMyPresence({ x: 0 }); * updateMyPresence({ y: 0 }); * * // At the next render, "myPresence" will be equal to "{ x: 0, y: 0 }" */ useMyPresence(): [ P, (patch: Partial

, options?: { addToHistory: boolean; }) => void ]; /** * useUpdateMyPresence is similar to useMyPresence but it only returns the function to update the current user presence. * 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. * * @example * const updateMyPresence = useUpdateMyPresence(); * updateMyPresence({ x: 0 }); * updateMyPresence({ y: 0 }); * * // At the next render, the presence of the current user will be equal to "{ x: 0, y: 0 }" */ useUpdateMyPresence(): (patch: Partial

, options?: { addToHistory: boolean; }) => void; /** * Create a callback function that lets you mutate Liveblocks state. * * The first argument that gets passed into your callback will be * a "mutation context", which exposes the following: * * - `storage` - The mutable Storage root. * You can mutate any Live structures with this, for example: * `storage.get('layers').get('layer1').set('fill', 'red')` * * - `setMyPresence` - Call this with a new (partial) Presence value. * * - `self` - A read-only version of the latest self, if you need it to * compute the next state. * * - `others` - A read-only version of the latest others list, if you * need it to compute the next state. * * useMutation is like React's useCallback, except that the first argument * that gets passed into your callback will be a "mutation context". * * If you want get access to the immutable root somewhere in your mutation, * you can use `storage.toJSON()`. * * @example * const fillLayers = useMutation( * ({ storage }, color: Color) => { * ... * }, * [], * ); * * fillLayers('red'); * * const deleteLayers = useMutation( * ({ storage }) => { * ... * }, * [], * ); * * deleteLayers(); */ useMutation, ...args: any[]) => any>(callback: F, deps: readonly unknown[]): OmitFirstArg; /** * Returns an array with information about all the users currently connected * in the room (except yourself). * * @example * const others = useOthers(); * * // Example to map all cursors in JSX * return ( * <> * {others.map((user) => { * if (user.presence.cursor == null) { * return null; * } * return * })} * * ) */ useOthers(): readonly User[]; /** * Extract arbitrary data based on all the users currently connected in the * room (except yourself). * * The selector function will get re-evaluated any time a user enters or * leaves the room, as well as whenever their presence data changes. * * The component that uses this hook will automatically re-render if your * selector function returns a different value from its previous run. * * By default `useOthers()` uses strict `===` to check for equality. Take * extra care when returning a computed object or list, for example when you * return the result of a .map() or .filter() call from the selector. In * those cases, you'll probably want to use a `shallow` comparison check. * * @example * const avatars = useOthers(users => users.map(u => u.info.avatar), shallow); * const cursors = useOthers(users => users.map(u => u.presence.cursor), shallow); * const someoneIsTyping = useOthers(users => users.some(u => u.presence.isTyping)); * */ useOthers(selector: (others: readonly User[]) => T, isEqual?: (prev: T, curr: T) => boolean): T; /** * Returns an array of connection IDs. This matches the values you'll get by * using the `useOthers()` hook. * * Roughly equivalent to: * useOthers((others) => others.map(other => other.connectionId), shallow) * * This is useful in particular to implement efficiently rendering components * for each user in the room, e.g. cursors. * * @example * const ids = useOthersConnectionIds(); * // [2, 4, 7] */ useOthersConnectionIds(): readonly number[]; /** * Related to useOthers(), but optimized for selecting only "subsets" of * others. This is useful for performance reasons in particular, because * selecting only a subset of users also means limiting the number of * re-renders that will be triggered. * * @example * const avatars = useOthersMapped(user => user.info.avatar); * // ^^^^^^^ * // { connectionId: number; data: string }[] * * The selector function you pass to useOthersMapped() is called an "item * selector", and operates on a single user at a time. If you provide an * (optional) "item comparison" function, it will be used to compare each * item pairwise. * * For example, to select multiple properties: * * @example * const avatarsAndCursors = useOthersMapped( * user => [u.info.avatar, u.presence.cursor], * shallow, // 👈 * ); */ useOthersMapped(itemSelector: (other: User) => T, itemIsEqual?: (prev: T, curr: T) => boolean): ReadonlyArray; /** * Given a connection ID (as obtained by using `useOthersConnectionIds`), you * can call this selector deep down in your component stack to only have the * component re-render if properties for this particular user change. * * @example * // Returns only the selected values re-renders whenever that selection changes) * const { x, y } = useOther(2, user => user.presence.cursor); */ useOther(connectionId: number, selector: (other: User) => T, isEqual?: (prev: T, curr: T) => boolean): T; /** * Returns a function that creates a thread with an initial comment, and optionally some metadata. * * @example * const createThread = useCreateThread(); * createThread({ body: {}, metadata: {} }); */ useCreateThread(): (options: CreateThreadOptions) => ThreadData; /** * Returns a function that deletes a thread and its associated comments. * Only the thread creator can delete a thread, it will throw otherwise. * * @example * const deleteThread = useDeleteThread(); * deleteThread("th_xxx"); */ useDeleteThread(): (threadId: string) => void; /** * Returns a function that edits a thread's metadata. * To delete an existing metadata property, set its value to `null`. * * @example * const editThreadMetadata = useEditThreadMetadata(); * editThreadMetadata({ threadId: "th_xxx", metadata: {} }) */ useEditThreadMetadata(): (options: EditThreadMetadataOptions) => void; /** * Returns a function that marks a thread as resolved. * * @example * const markThreadAsResolved = useMarkThreadAsResolved(); * markThreadAsResolved("th_xxx"); */ useMarkThreadAsResolved(): (threadId: string) => void; /** * Returns a function that marks a thread as unresolved. * * @example * const markThreadAsUnresolved = useMarkThreadAsUnresolved(); * markThreadAsUnresolved("th_xxx"); */ useMarkThreadAsUnresolved(): (threadId: string) => void; /** * Returns a function that subscribes the user to a thread. * * @example * const subscribeToThread = useSubscribeToThread(); * subscribeToThread("th_xxx"); */ useSubscribeToThread(): (threadId: string) => void; /** * Returns a function that unsubscribes the user from a thread. * * @example * const unsubscribeFromThread = useUnsubscribeFromThread(); * unsubscribeFromThread("th_xxx"); */ useUnsubscribeFromThread(): (threadId: string) => void; /** * Returns a function that adds a comment to a thread. * * @example * const createComment = useCreateComment(); * createComment({ threadId: "th_xxx", body: {} }); */ useCreateComment(): (options: CreateCommentOptions) => CommentData; /** * Returns a function that edits a comment. * * @example * const editComment = useEditComment() * editComment({ threadId: "th_xxx", commentId: "cm_xxx", body: {} }) */ useEditComment(): (options: EditCommentOptions) => void; /** * Returns a function that edits a comment's metadata. * To delete an existing metadata property, set its value to `null`. * * @example * const editCommentMetadata = useEditCommentMetadata(); * editCommentMetadata({ threadId: "th_xxx", commentId: "cm_xxx", metadata: { tag: "important", externalId: 1234 } }) */ useEditCommentMetadata(): (options: EditCommentMetadataOptions) => void; /** * Returns a function that deletes a comment. * If it is the last non-deleted comment, the thread also gets deleted. * * @example * const deleteComment = useDeleteComment(); * deleteComment({ threadId: "th_xxx", commentId: "cm_xxx" }) */ useDeleteComment(): (options: DeleteCommentOptions) => void; /** * Returns a function that adds a reaction from a comment. * * @example * const addReaction = useAddReaction(); * addReaction({ threadId: "th_xxx", commentId: "cm_xxx", emoji: "👍" }) */ useAddReaction(): (options: CommentReactionOptions) => void; /** * Returns a function that removes a reaction on a comment. * * @example * const removeReaction = useRemoveReaction(); * removeReaction({ threadId: "th_xxx", commentId: "cm_xxx", emoji: "👍" }) */ useRemoveReaction(): (options: CommentReactionOptions) => void; /** * Returns a function that updates the user's subscription settings * for the current room. * * @example * const updateRoomSubscriptionSettings = useUpdateRoomSubscriptionSettings(); * updateRoomSubscriptionSettings({ threads: "all" }); */ useUpdateRoomSubscriptionSettings(): (settings: Partial) => void; /** * Returns a function that marks a thread as read. * * @example * const markThreadAsRead = useMarkThreadAsRead(); * markThreadAsRead("th_xxx"); */ useMarkThreadAsRead(): (threadId: string) => void; /** * Returns the subscription status of a thread, methods to update it, and when * the thread was last read. * * @example * const { status, subscribe, unsubscribe, unreadSince } = useThreadSubscription("th_xxx"); */ useThreadSubscription(threadId: string): ThreadSubscription; }; type RoomContextBundle

= Resolve & SharedContextBundle["classic"] & { /** * Extract arbitrary data from the Liveblocks Storage state, using an * arbitrary selector function. * * The selector function will get re-evaluated any time something changes in * Storage. The value returned by your selector function will also be the * value returned by the hook. * * The `root` value that gets passed to your selector function is * a immutable/readonly version of your Liveblocks storage root. * * The component that uses this hook will automatically re-render if the * returned value changes. * * By default `useStorage()` uses strict `===` to check for equality. Take * extra care when returning a computed object or list, for example when you * return the result of a .map() or .filter() call from the selector. In * those cases, you'll probably want to use a `shallow` comparison check. */ useStorage(selector: (root: ToJson) => T, isEqual?: (prev: T | null, curr: T | null) => boolean): T | null; /** * Gets the current user once it is connected to the room. * * @example * const me = useSelf(); * if (me !== null) { * const { x, y } = me.presence.cursor; * } */ useSelf(): User | null; /** * Extract arbitrary data based on the current user. * * The selector function will get re-evaluated any time your presence data * changes. * * The component that uses this hook will automatically re-render if your * selector function returns a different value from its previous run. * * By default `useSelf()` uses strict `===` to check for equality. Take extra * care when returning a computed object or list, for example when you return * the result of a .map() or .filter() call from the selector. In those * cases, you'll probably want to use a `shallow` comparison check. * * Will return `null` while Liveblocks isn't connected to a room yet. * * @example * const cursor = useSelf(me => me.presence.cursor); * if (cursor !== null) { * const { x, y } = cursor; * } * */ useSelf(selector: (me: User) => T, isEqual?: (prev: T, curr: T) => boolean): T | null; /** * Returns the threads within the current room. * * @example * const { threads, error, isLoading } = useThreads(); */ useThreads(options?: UseThreadsOptions): ThreadsAsyncResult; /** * Returns feeds for the current room. * * @example * const { feeds, error, isLoading } = useFeeds(); */ useFeeds(options?: UseFeedsOptions): FeedsAsyncResult; /** * Returns messages for a specific feed in the current room. * * @example * const { messages, error, isLoading } = useFeedMessages("feed-id"); */ useFeedMessages(feedId: string, options?: UseFeedMessagesOptions): FeedMessagesAsyncResult; /** * Returns a function that creates a new feed in the current room. * * @example * const createFeed = useCreateFeed(); * createFeed("feed-id", { metadata: { name: "My Feed" } }); */ useCreateFeed(): (feedId: string, options?: { metadata?: FeedCreateMetadata; createdAt?: number; }) => Promise; /** * Returns a function that deletes a feed from the current room. * * @example * const deleteFeed = useDeleteFeed(); * deleteFeed("feed-id"); */ useDeleteFeed(): (feedId: string) => Promise; /** * Returns a function that updates a feed's metadata in the current room. * * @example * const updateFeedMetadata = useUpdateFeedMetadata(); * updateFeedMetadata("feed-id", { name: "Updated Name" }); */ useUpdateFeedMetadata(): (feedId: string, metadata: FeedUpdateMetadata) => Promise; /** * Returns a function that adds a message to a feed in the current room. * * @example * const createFeedMessage = useCreateFeedMessage(); * createFeedMessage("feed-id", { text: "Hello" }); */ useCreateFeedMessage(): (feedId: string, data: JsonObject, options?: { id?: string; createdAt?: number; }) => Promise; /** * Returns a function that deletes a message from a feed in the current room. * * @example * const deleteFeedMessage = useDeleteFeedMessage(); * deleteFeedMessage("feed-id", "message-id"); */ useDeleteFeedMessage(): (feedId: string, messageId: string) => Promise; /** * Returns a function that updates a feed message in the current room. * * @example * const updateFeedMessage = useUpdateFeedMessage(); * updateFeedMessage("feed-id", "message-id", { text: "Updated" }); */ useUpdateFeedMessage(): (feedId: string, messageId: string, data: JsonObject, options?: { updatedAt?: number; }) => Promise; /** * Returns the result of searching comments by text in the current room. The result includes the id and the plain text content of the matched comments along with the parent thread id of the comment. * * @example * const { results, error, isLoading } = useSearchComments({ query: { text: "hello"} }); */ useSearchComments(options: UseSearchCommentsOptions): SearchCommentsAsyncResult; /** * Returns the user's subscription settings for the current room * and a function to update them. * * @example * const [{ settings }, updateSettings] = useRoomSubscriptionSettings(); */ useRoomSubscriptionSettings(): [ RoomSubscriptionSettingsAsyncResult, (settings: Partial) => void ]; /** * Returns a presigned URL for an attachment by its ID. * * @example * const { url, error, isLoading } = useAttachmentUrl("at_xxx"); */ useAttachmentUrl(attachmentId: string): AttachmentUrlAsyncResult; /** * (Private beta) Returns a history of versions of the current room. * * @example * const { versions, error, isLoading } = useHistoryVersions(); */ useHistoryVersions(): HistoryVersionsAsyncResult; /** * (Private beta) Returns the data of a specific version of the current room. * * @example * const { data, error, isLoading } = useHistoryVersionData(version.id); */ useHistoryVersionData(id: string): HistoryVersionDataAsyncResult; suspense: Resolve & SharedContextBundle["suspense"] & { /** * Extract arbitrary data from the Liveblocks Storage state, using an * arbitrary selector function. * * The selector function will get re-evaluated any time something changes in * Storage. The value returned by your selector function will also be the * value returned by the hook. * * The `root` value that gets passed to your selector function is * a immutable/readonly version of your Liveblocks storage root. * * The component that uses this hook will automatically re-render if the * returned value changes. * * By default `useStorage()` uses strict `===` to check for equality. Take * extra care when returning a computed object or list, for example when you * return the result of a .map() or .filter() call from the selector. In * those cases, you'll probably want to use a `shallow` comparison check. */ useStorage(selector: (root: ToJson) => T, isEqual?: (prev: T, curr: T) => boolean): T; /** * Gets the current user once it is connected to the room. * * @example * const me = useSelf(); * const { x, y } = me.presence.cursor; */ useSelf(): User; /** * Extract arbitrary data based on the current user. * * The selector function will get re-evaluated any time your presence data * changes. * * The component that uses this hook will automatically re-render if your * selector function returns a different value from its previous run. * * By default `useSelf()` uses strict `===` to check for equality. Take extra * care when returning a computed object or list, for example when you return * the result of a .map() or .filter() call from the selector. In those * cases, you'll probably want to use a `shallow` comparison check. * * @example * const cursor = useSelf(me => me.presence.cursor); * const { x, y } = cursor; * */ useSelf(selector: (me: User) => T, isEqual?: (prev: T, curr: T) => boolean): T; /** * Returns the threads within the current room. * * @example * const { threads } = useThreads(); */ useThreads(options?: UseThreadsOptions): ThreadsAsyncSuccess; /** * Returns feeds for the current room. * * @example * const { feeds } = useFeeds(); */ useFeeds(options?: UseFeedsOptions): FeedsAsyncSuccess; /** * Returns messages for a specific feed in the current room. * * @example * const { messages } = useFeedMessages("feed-id"); */ useFeedMessages(feedId: string, options?: UseFeedMessagesOptions): FeedMessagesAsyncSuccess; useCreateFeed(): (feedId: string, options?: { metadata?: FeedCreateMetadata; createdAt?: number; }) => Promise; useDeleteFeed(): (feedId: string) => Promise; useUpdateFeedMetadata(): (feedId: string, metadata: FeedUpdateMetadata) => Promise; useCreateFeedMessage(): (feedId: string, data: JsonObject, options?: { id?: string; createdAt?: number; }) => Promise; useDeleteFeedMessage(): (feedId: string, messageId: string) => Promise; useUpdateFeedMessage(): (feedId: string, messageId: string, data: JsonObject, options?: { updatedAt?: number; }) => Promise; /** * (Private beta) Returns a history of versions of the current room. * * @example * const { versions } = useHistoryVersions(); */ useHistoryVersions(): HistoryVersionsAsyncSuccess; /** * Returns the user's subscription settings for the current room * and a function to update them. * * @example * const [{ settings }, updateSettings] = useRoomSubscriptionSettings(); */ useRoomSubscriptionSettings(): [ RoomSubscriptionSettingsAsyncSuccess, (settings: Partial) => void ]; /** * Returns a presigned URL for an attachment by its ID. * * @example * const { url } = useAttachmentUrl("at_xxx"); */ useAttachmentUrl(attachmentId: string): AttachmentUrlAsyncSuccess; }>; }>; /** * Properties that are the same in LiveblocksContext and LiveblocksContext["suspense"]. */ type LiveblocksContextBundleCommon = { /** * Makes Liveblocks features outside of rooms (e.g. Notifications) available * in the component hierarchy below. */ LiveblocksProvider(props: PropsWithChildren): JSX.Element; /** * Returns a function that marks an inbox notification as read for the current user. * * @example * const markInboxNotificationAsRead = useMarkInboxNotificationAsRead(); * markInboxNotificationAsRead("in_xxx"); */ useMarkInboxNotificationAsRead(): (inboxNotificationId: string) => void; /** * Returns a function that marks all of the current user's inbox notifications as read. * * @example * const markAllInboxNotificationsAsRead = useMarkAllInboxNotificationsAsRead(); * markAllInboxNotificationsAsRead(); */ useMarkAllInboxNotificationsAsRead(): () => void; /** * Returns a function that deletes an inbox notification for the current user. * * @example * const deleteInboxNotification = useDeleteInboxNotification(); * deleteInboxNotification("in_xxx"); */ useDeleteInboxNotification(): (inboxNotificationId: string) => void; /** * Returns a function that deletes all of the current user's inbox notifications. * * @example * const deleteAllInboxNotifications = useDeleteAllInboxNotifications(); * deleteAllInboxNotifications(); */ useDeleteAllInboxNotifications(): () => void; /** * Returns the thread associated with a `"thread"` inbox notification. * * It can **only** be called with IDs of `"thread"` inbox notifications, * so we recommend only using it when customizing the rendering or in other * situations where you can guarantee the kind of the notification. * * When `useInboxNotifications` returns `"thread"` inbox notifications, * it also receives the associated threads and caches them behind the scenes. * When you call `useInboxNotificationThread`, it simply returns the cached thread * for the inbox notification ID you passed to it, without any fetching or waterfalls. * * @example * const thread = useInboxNotificationThread("in_xxx"); */ useInboxNotificationThread(inboxNotificationId: string): ThreadData; /** * Returns notification settings for the current user. * * @example * const [{ settings }, updateNotificationSettings] = useNotificationSettings() */ useNotificationSettings(): [ NotificationSettingsAsyncResult, (settings: PartialNotificationSettings) => void ]; /** * Returns a function that updates the user's notification * settings for a project. * * @example * const updateNotificationSettings = useUpdateNotificationSettings() */ useUpdateNotificationSettings(): (settings: PartialNotificationSettings) => void; /** * Returns the current Liveblocks sync status, and triggers a re-render * whenever it changes. Can be used to render a "Saving..." indicator, or for * preventing that a browser tab can be closed until all changes have been * synchronized with the server. * * @example * const syncStatus = useSyncStatus(); // "synchronizing" | "synchronized" * const syncStatus = useSyncStatus({ smooth: true }); */ useSyncStatus(options?: UseSyncStatusOptions): SyncStatus; /** * Returns a function that creates an AI chat. * * If you do not pass a title for the chat, it will be automatically computed * after the first AI response. * * @example * const createAiChat = useCreateAiChat(); * * // Create a chat with an automatically generated title * createAiChat("ai-chat-id"); * * // Create a chat with a custom title * createAiChat({ id: "ai-chat-id", title: "My AI chat" }); */ useCreateAiChat(): { (chatId: string): void; (options: CreateAiChatOptions): void; }; /** * Returns a function that deletes the AI chat with the specified id. * * @example * const deleteAiChat = useDeleteAiChat(); * deleteAiChat("ai-chat-id"); */ useDeleteAiChat(): (chatId: string) => void; /** * Returns a function to send a message in an AI chat. * * @example * const sendAiMessage = useSendAiMessage("chat-id"); * sendAiMessage("Hello, Liveblocks AI!"); * * You can set options related to the message being sent, such as the copilot ID to use. * * @example * const sendAiMessage = useSendAiMessage("chat-id", { copilotId: "co_xxx" }); * sendAiMessage("Hello, Liveblocks AI!"); * * @example * const sendAiMessage = useSendAiMessage("chat-id", { copilotId: "co_xxx" }); * sendAiMessage({ text: "Hello, Liveblocks AI!", copilotId: "co_yyy" }); */ useSendAiMessage(chatId: string, options?: UseSendAiMessageOptions): { (text: string): AiUserMessage; (options: SendAiMessageOptions): AiUserMessage; }; /** * Returns a function to send a message in an AI chat. * * @example * const sendAiMessage = useSendAiMessage(); * sendAiMessage({ chatId: "chat-id", text: "Hello, Liveblocks AI!" }); * * You can set options related to the message being sent, such as the copilot ID to use. * * @example * const sendAiMessage = useSendAiMessage(); * sendAiMessage({ chatId: "chat-id", text: "Hello, Liveblocks AI!", copilotId: "co_xxx" }); */ useSendAiMessage(): (message: WithRequired) => AiChatMessage; /** * Returns a function to send a message in an AI chat. * * @example * const sendAiMessage = useSendAiMessage(chatId); * sendAiMessage("Hello, Liveblocks AI!"); * * You can set options related to the message being sent, such as the copilot ID to use. * * @example * const sendAiMessage = useSendAiMessage(chatId, { copilotId: "co_xxx" }); * sendAiMessage("Hello, Liveblocks AI!"); * * You can also pass the chat ID dynamically if it's not known when calling the hook. * * @example * const sendAiMessage = useSendAiMessage(); * sendAiMessage({ chatId: "chat-id", text: "Hello, Liveblocks AI!" }); * * @example * const sendAiMessage = useSendAiMessage(); * sendAiMessage({ chatId: "chat-id", text: "Hello, Liveblocks AI!", copilotId: "co_xxx" }); */ useSendAiMessage(chatId?: string, options?: UseSendAiMessageOptions): { (text: string): AiUserMessage; (options: SendAiMessageOptions): AiUserMessage; (options: WithRequired): AiUserMessage; }; }; type LiveblocksContextBundle = Resolve & SharedContextBundle["classic"] & { /** * Returns the inbox notifications for the current user. * * @example * const { inboxNotifications, error, isLoading } = useInboxNotifications(); */ useInboxNotifications(options?: UseInboxNotificationsOptions): InboxNotificationsAsyncResult; /** * Returns the number of unread inbox notifications for the current user. * * @example * const { count, error, isLoading } = useUnreadInboxNotificationsCount(); */ useUnreadInboxNotificationsCount(options?: UseInboxNotificationsOptions): UnreadInboxNotificationsCountAsyncResult; /** * @experimental * * This hook is experimental and could be removed or changed at any time! * Do not use unless explicitly recommended by the Liveblocks team. */ useUserThreads_experimental(options?: UseUserThreadsOptions): ThreadsAsyncResult; /** * (Private beta) Returns the chats for the current user. * * @example * const { chats, error, isLoading } = useAiChats(); */ useAiChats(options?: UseAiChatsOptions): AiChatsAsyncResult; /** * (Private beta) Returns the messages in the given chat. * * @example * const { messages, error, isLoading } = useAiChatMessages("my-chat"); */ useAiChatMessages(chatId: string): AiChatMessagesAsyncResult; /** * (Private beta) Returns the information of the given chat. * * @example * const { chat, error, isLoading } = useAiChat("my-chat"); */ useAiChat(chatId: string): AiChatAsyncResult; /** * Returns the status of an AI chat, indicating whether it's idle or actively * generating content. This is a convenience hook that derives its state from * the latest assistant message in the chat. * * Re-renders whenever any of the relevant fields change. * * @param chatId - The ID of the chat to monitor * @returns The current status of the AI chat * * @example * ```tsx * import { useAiChatStatus } from "@liveblocks/react"; * * function ChatStatus() { * const { status, partType, toolName } = useAiChatStatus("my-chat"); * console.log(status); // "loading" | "idle" | "generating" * console.log(status.partType); // "text" | "tool-invocation" | ... * console.log(status.toolName); // string | undefined * } * ``` */ useAiChatStatus(chatId: string, branchId?: MessageId): AiChatStatus; /** * Returns metadata for a given URL. * * @example * const { metadata, error, isLoading } = useUrlMetadata("https://liveblocks.io"); */ useUrlMetadata(url: string): UrlMetadataAsyncResult; suspense: Resolve & SharedContextBundle["suspense"] & { /** * Returns the inbox notifications for the current user. * * @example * const { inboxNotifications } = useInboxNotifications(); */ useInboxNotifications(options?: UseInboxNotificationsOptions): InboxNotificationsAsyncSuccess; /** * Returns the number of unread inbox notifications for the current user. * * @example * const { count } = useUnreadInboxNotificationsCount(); */ useUnreadInboxNotificationsCount(options?: UseInboxNotificationsOptions): UnreadInboxNotificationsCountAsyncSuccess; /** * Returns notification settings for the current user. * * @example * const [{ settings }, updateNotificationSettings] = useNotificationSettings() */ useNotificationSettings(): [ NotificationSettingsAsyncResult, (settings: PartialNotificationSettings) => void ]; /** * @experimental * * This hook is experimental and could be removed or changed at any time! * Do not use unless explicitly recommended by the Liveblocks team. */ useUserThreads_experimental(options?: UseUserThreadsOptions): ThreadsAsyncSuccess; /** * (Private beta) Returns the chats for the current user. * * @example * const { chats } = useAiChats(); */ useAiChats(options?: UseAiChatsOptions): AiChatsAsyncSuccess; /** * (Private beta) Returns the messages in the given chat. * * @example * const { messages } = useAiChatMessages("my-chat"); */ useAiChatMessages(chatId: string): AiChatMessagesAsyncSuccess; /** * (Private beta) Returns the information of the given chat. * * @example * const { chat, error, isLoading } = useAiChat("my-chat"); */ useAiChat(chatId: string): AiChatAsyncSuccess; /** * Returns the status of an AI chat, indicating whether it's idle or actively * generating content. This is a convenience hook that derives its state from * the latest assistant message in the chat. * * Re-renders whenever any of the relevant fields change. * * @param chatId - The ID of the chat to monitor * @returns The current status of the AI chat * * @example * ```tsx * import { useAiChatStatus } from "@liveblocks/react"; * * function ChatStatus() { * const { status, partType, toolName } = useAiChatStatus("my-chat"); * console.log(status); // "loading" | "idle" | "generating" * console.log(status.partType); // "text" | "tool-invocation" | ... * console.log(status.toolName); // string | undefined * } * ``` */ useAiChatStatus(chatId: string, branchId?: MessageId): AiChatStatus; /** * Returns metadata for a given URL. * * @example * const { metadata } = useUrlMetadata("https://liveblocks.io"); */ useUrlMetadata(url: string): UrlMetadataAsyncSuccess; }>; }>; type ReadonlyThreadDB = Omit, "upsert" | "delete" | "signal">; /** * This class implements a lightweight, in-memory, "database" for all Thread * instances. * * It exposes the following methods: * * - upsert: To add/update a thread * - upsertIfNewer: To add/update a thread. Only update an existing thread if * its newer * - delete: To mark existing threads as deleted * - get: To get any non-deleted thread * - getEvenIfDeleted: To get a thread which is possibly deleted * - findMany: To filter an ordered list of non-deleted threads * - clone: To clone the DB to mutate it further. This is used to mix in * optimistic updates without losing the original thread contents. * */ declare class ThreadDB { #private; readonly signal: MutableSignal; constructor(); clone(): ThreadDB; /** Returns an existing thread by ID. Will never return a deleted thread. */ get(threadId: string): ThreadData | undefined; /** Returns the (possibly deleted) thread by ID. */ getEvenIfDeleted(threadId: string): ThreadDataWithDeleteInfo | undefined; /** Adds or updates a thread in the DB. If the newly given thread is a deleted one, it will get deleted. */ upsert(thread: ThreadDataWithDeleteInfo): void; /** Like .upsert(), except it won't update if a thread by this ID already exists. */ upsertIfNewer(thread: ThreadDataWithDeleteInfo): void; applyDelta(newThreads: ThreadData[], deletedThreads: ThreadDeleteInfo[]): void; /** * Marks a thread as deleted. It will no longer pop up in .findMany() * queries, but it can still be accessed via `.getEvenIfDeleted()`. */ delete(threadId: string, deletedAt: Date): void; /** * Returns all threads matching a given roomId and query. If roomId is not * specified, it will return all threads matching the query, across all * rooms. * * Returns the results in the requested order. Please note: * 'asc' means by createdAt ASC * 'desc' means by updatedAt DESC * * Will never return deleted threads in the result. * * Subscriptions are needed to filter threads based on the user's subscriptions. */ findMany(roomId: string | undefined, query: ThreadsQuery | undefined, direction: "asc" | "desc", subscriptions?: Record): ThreadData[]; } type OptimisticUpdate = CreateThreadOptimisticUpdate | DeleteThreadOptimisticUpdate | EditThreadMetadataOptimisticUpdate | MarkThreadAsResolvedOptimisticUpdate | MarkThreadAsUnresolvedOptimisticUpdate | SubscribeToThreadOptimisticUpdate | UnsubscribeFromThreadOptimisticUpdate | CreateCommentOptimisticUpdate | EditCommentOptimisticUpdate | EditCommentMetadataOptimisticUpdate | DeleteCommentOptimisticUpdate | AddReactionOptimisticUpdate | RemoveReactionOptimisticUpdate | MarkInboxNotificationAsReadOptimisticUpdate | MarkAllInboxNotificationsAsReadOptimisticUpdate | DeleteInboxNotificationOptimisticUpdate | DeleteAllInboxNotificationsOptimisticUpdate | UpdateRoomSubscriptionSettingsOptimisticUpdate | UpdateNotificationSettingsOptimisticUpdate; type CreateThreadOptimisticUpdate = { type: "create-thread"; id: string; roomId: string; thread: ThreadData; }; type DeleteThreadOptimisticUpdate = { type: "delete-thread"; id: string; roomId: string; threadId: string; deletedAt: Date; }; type EditThreadMetadataOptimisticUpdate = { type: "edit-thread-metadata"; id: string; threadId: string; metadata: Resolve>; updatedAt: Date; }; type MarkThreadAsResolvedOptimisticUpdate = { type: "mark-thread-as-resolved"; id: string; threadId: string; updatedAt: Date; }; type MarkThreadAsUnresolvedOptimisticUpdate = { type: "mark-thread-as-unresolved"; id: string; threadId: string; updatedAt: Date; }; type SubscribeToThreadOptimisticUpdate = { type: "subscribe-to-thread"; id: string; threadId: string; subscribedAt: Date; }; type UnsubscribeFromThreadOptimisticUpdate = { type: "unsubscribe-from-thread"; id: string; threadId: string; unsubscribedAt: Date; }; type CreateCommentOptimisticUpdate = { type: "create-comment"; id: string; comment: CommentData; }; type EditCommentOptimisticUpdate = { type: "edit-comment"; id: string; comment: CommentData; }; type EditCommentMetadataOptimisticUpdate = { type: "edit-comment-metadata"; id: string; threadId: string; commentId: string; metadata: Resolve>; updatedAt: Date; }; type DeleteCommentOptimisticUpdate = { type: "delete-comment"; id: string; roomId: string; threadId: string; deletedAt: Date; commentId: string; }; type AddReactionOptimisticUpdate = { type: "add-reaction"; id: string; threadId: string; commentId: string; reaction: CommentUserReaction; }; type RemoveReactionOptimisticUpdate = { type: "remove-reaction"; id: string; threadId: string; commentId: string; emoji: string; userId: string; removedAt: Date; }; type MarkInboxNotificationAsReadOptimisticUpdate = { type: "mark-inbox-notification-as-read"; id: string; inboxNotificationId: string; readAt: Date; }; type MarkAllInboxNotificationsAsReadOptimisticUpdate = { type: "mark-all-inbox-notifications-as-read"; id: string; readAt: Date; }; type DeleteInboxNotificationOptimisticUpdate = { type: "delete-inbox-notification"; id: string; inboxNotificationId: string; deletedAt: Date; }; type DeleteAllInboxNotificationsOptimisticUpdate = { type: "delete-all-inbox-notifications"; id: string; deletedAt: Date; }; type UpdateRoomSubscriptionSettingsOptimisticUpdate = { type: "update-room-subscription-settings"; id: string; roomId: string; userId: string; settings: Partial; }; type UpdateNotificationSettingsOptimisticUpdate = { type: "update-notification-settings"; id: string; settings: PartialNotificationSettings; }; /** * Like Promise, except it will have a synchronously readable `status` * field, indicating the status of the promise. * This is compatible with React's `use()` promises, hence the name. */ type UsablePromise = Promise & ({ status: "pending"; } | { status: "rejected"; reason: Error; } | { status: "fulfilled"; value: T; }); type LoadableResource = { signal: ISignal; waitUntilLoaded: () => UsablePromise; }; type RoomId = string; type UserQueryKey = string; type RoomQueryKey = string; type InboxNotificationsQueryKey = string; type AiChatsQueryKey = string; /** * A lookup table (LUT) for all the inbox notifications. */ type NotificationsLUT = Map; /** * Room subscription settings by room ID. * e.g. { 'room-abc': { threads: "all" }, * 'room-def': { threads: "replies_and_mentions" }, * 'room-xyz': { threads: "none" }, * } */ type RoomSubscriptionSettingsByRoomId = Record; type SubscriptionsByKey = Record; type CleanThreadifications = CleanThreads & CleanNotifications; type CleanThreads = { /** * Keep track of loading and error status of all the queries made by the client. * e.g. 'room-abc-{"color":"red"}' - ok * e.g. 'room-abc-{}' - loading */ threadsDB: ReadonlyThreadDB; }; type CleanNotifications = { /** * All inbox notifications in a sorted array, optimistic updates applied. */ sortedNotifications: InboxNotificationData[]; /** * Inbox notifications by ID. * e.g. `in_${string}` */ notificationsById: Record; }; type CleanThreadSubscriptions = { /** * Thread subscriptions by key (kind + subject ID). * e.g. `thread:${string}`, `$custom:${string}`, etc */ subscriptions: SubscriptionsByKey; /** * All inbox notifications in a sorted array, optimistic updates applied. * * `useThreadSubscription` returns the subscription status based on subscriptions * but also the `readAt` value of the associated notification, so we need to * expose the notifications here as well. */ notifications: InboxNotificationData[]; }; declare function createStore_forNotifications(): { signal: ISignal; markAllRead: (readAt: Date) => void; markRead: (notificationId: string, readAt: Date) => void; delete: (inboxNotificationId: string) => void; applyDelta: (newNotifications: InboxNotificationData[], deletedNotifications: InboxNotificationDeleteInfo[]) => void; clear: () => void; updateAssociatedNotification: (newComment: CommentData) => void; upsert: (notification: InboxNotificationData) => void; }; declare function createStore_forUnreadNotificationsCount(): { signal: DerivedSignal<{ [k: string]: number; }>; update: (queryKey: InboxNotificationsQueryKey, count: number) => void; }; declare function createStore_forSubscriptions(updates: ISignal[]>, threads: ReadonlyThreadDB): { signal: DerivedSignal; applyDelta: (newSubscriptions: SubscriptionData[], deletedSubscriptions: SubscriptionDeleteInfo[]) => void; create: (subscription: SubscriptionData) => void; delete: (subscriptionKey: SubscriptionKey) => void; }; declare function createStore_forRoomSubscriptionSettings(updates: ISignal[]>): { signal: DerivedSignal; update: (roomId: string, settings: RoomSubscriptionSettings$1) => void; }; declare function createStore_forHistoryVersions(): { signal: DerivedSignal<{ [k: string]: { [k: string]: HistoryVersion; }; }>; update: (roomId: string, versions: HistoryVersion[]) => void; }; declare function createStore_forUrlsMetadata(): { signal: DerivedSignal<{ [k: string]: UrlMetadata; }>; update: (url: string, metadata: UrlMetadata) => void; }; declare function createStore_forPermissionHints(): { getPermissionForRoomΣ: (roomId: string) => ISignal>; update: (newHints: Record) => void; }; /** * Notification settings * * e.g. * { * email: { * thread: true, * textMention: false, * $customKind: true | false, * } * slack: { * thread: true, * textMention: false, * $customKind: true | false, * } * } * e.g. {} when before the first successful fetch. */ declare function createStore_forNotificationSettings(updates: ISignal[]>): { signal: DerivedSignal; update: (settings: NotificationSettings) => void; }; declare function createStore_forOptimistic(client: Client$1): { signal: ISignal[]>; add: (optimisticUpdate: DistributiveOmit, "id">) => string; remove: (optimisticId: string) => void; }; declare class UmbrellaStore { #private; readonly threads: ThreadDB; readonly notifications: ReturnType; readonly subscriptions: ReturnType; readonly roomSubscriptionSettings: ReturnType; readonly historyVersions: ReturnType; readonly unreadNotificationsCount: ReturnType; readonly urlsMetadata: ReturnType; readonly permissionHints: ReturnType; readonly notificationSettings: ReturnType; readonly optimisticUpdates: ReturnType>; readonly outputs: { readonly threadifications: DerivedSignal>; readonly threads: DerivedSignal>; readonly loadingRoomThreads: DefaultMap>>; readonly loadingUserThreads: DefaultMap>>; readonly notifications: DerivedSignal; readonly threadSubscriptions: DerivedSignal; readonly loadingNotifications: DefaultMap>; readonly unreadNotificationsCount: DefaultMap>; readonly roomSubscriptionSettingsByRoomId: DefaultMap>; readonly versionsByRoomId: DefaultMap>; readonly notificationSettings: LoadableResource; readonly aiChats: DefaultMap>; readonly messagesByChatId: DefaultMap>>; readonly aiChatById: DefaultMap>; readonly urlMetadataByUrl: DefaultMap>; readonly loadingFeeds: DefaultMap>; readonly loadingFeedMessages: DefaultMap>; }; constructor(client: OpaqueClient); /** * Updates an existing inbox notification with a new value, replacing the * corresponding optimistic update. * * This will not update anything if the inbox notification ID isn't found. */ markInboxNotificationRead(inboxNotificationId: string, readAt: Date, optimisticId: string): void; markAllInboxNotificationsRead(optimisticId: string, readAt: Date): void; /** * Deletes an existing inbox notification, replacing the corresponding * optimistic update. */ deleteInboxNotification(inboxNotificationId: string, optimisticId: string): void; /** * Deletes *all* inbox notifications, replacing the corresponding optimistic * update. */ deleteAllInboxNotifications(optimisticId: string): void; /** * Creates an existing subscription, replacing the corresponding * optimistic update. */ createSubscription(subscription: SubscriptionData, optimisticId: string): void; /** * Deletes an existing subscription, replacing the corresponding * optimistic update. */ deleteSubscription(subscriptionKey: SubscriptionKey, optimisticId: string): void; /** * Creates an new thread, replacing the corresponding optimistic update. */ createThread(optimisticId: string, thread: Readonly>): void; patchThread(threadId: string, optimisticId: string | null, patch: { metadata?: TM; resolved?: boolean; }, updatedAt: Date): void; addReaction(threadId: string, optimisticId: string | null, commentId: string, reaction: CommentUserReaction, createdAt: Date): void; removeReaction(threadId: string, optimisticId: string | null, commentId: string, emoji: string, userId: string, removedAt: Date): void; /** * Soft-deletes an existing thread by setting its `deletedAt` value, * replacing the corresponding optimistic update. * * This will not update anything if: * - The thread ID isn't found; or * - The thread ID was already deleted */ deleteThread(threadId: string, optimisticId: string | null): void; /** * Creates an existing comment and ensures the associated notification is * updated correctly, replacing the corresponding optimistic update. */ createComment(newComment: CommentData, optimisticId: string): void; editComment(threadId: string, optimisticId: string, editedComment: CommentData): void; editCommentMetadata(threadId: string, commentId: string, optimisticId: string, updatedMetadata: CM, updatedAt: Date): void; deleteComment(threadId: string, optimisticId: string, commentId: string, deletedAt: Date): void; updateThreadifications(threads: ThreadData[], notifications: InboxNotificationData[], subscriptions: SubscriptionData[], deletedThreads?: ThreadDeleteInfo[], deletedNotifications?: InboxNotificationDeleteInfo[], deletedSubscriptions?: SubscriptionDeleteInfo[]): void; /** * Updates existing subscription settings for a room with a new value, * replacing the corresponding optimistic update. */ updateRoomSubscriptionSettings(roomId: string, optimisticId: string, settings: Readonly): void; fetchNotificationsDeltaUpdate(signal: AbortSignal): Promise; /** * Upserts feeds in the cache (for list/added/updated operations). */ upsertFeeds(roomId: RoomId, feeds: readonly Feed[]): void; /** * Removes a feed from the cache (for deleted operations). */ deleteFeed(roomId: RoomId, feedId: string): void; /** * Upserts feed messages in the cache (for list/added/updated operations). */ upsertFeedMessages(_roomId: RoomId, feedId: string, messages: readonly FeedMessage[]): void; /** * Removes feed messages from the cache (for deleted operations). */ deleteFeedMessages(_roomId: RoomId, feedId: string, messageIds: readonly string[]): void; fetchUnreadNotificationsCount(queryKey: InboxNotificationsQueryKey, signal: AbortSignal): Promise; fetchRoomThreadsDeltaUpdate(roomId: string, signal: AbortSignal): Promise; fetchUserThreadsDeltaUpdate(signal: AbortSignal): Promise; fetchRoomVersionsDeltaUpdate(roomId: string, signal: AbortSignal): Promise; refreshRoomSubscriptionSettings(roomId: string, signal: AbortSignal): Promise; /** * Refresh notification settings from poller */ refreshNotificationSettings(signal: AbortSignal): Promise; /** * Updates notification settings with a new value, replacing the * corresponding optimistic update. */ updateNotificationSettings_confirmOptimisticUpdate(settings: NotificationSettings, optimisticUpdateId: string): void; } /** * Gets or creates a unique Umbrella store for each unique client instance. * * @private */ declare function getUmbrellaStoreForClient(client: OpaqueClient): UmbrellaStore; /** * Returns a function that creates an AI chat. * * If you do not pass a title for the chat, it will be automatically computed * after the first AI response. * * @example * const createAiChat = useCreateAiChat(); * * // Create a chat with an automatically generated title * createAiChat("ai-chat-id"); * * // Create a chat with a custom title * createAiChat({ id: "ai-chat-id", title: "My AI chat" }); */ declare function useCreateAiChat(): { (chatId: string): void; (options: CreateAiChatOptions): void; }; /** * Returns a function that deletes the AI chat with the specified id. * * @example * const deleteAiChat = useDeleteAiChat(); * deleteAiChat("ai-chat-id"); */ declare function useDeleteAiChat(): (chatId: string) => void; /** * Returns the status of an AI chat, indicating whether it's disconnected, loading, idle * or actively generating content. This is a convenience hook that derives its state from * the latest assistant message in the chat. * * Re-renders whenever any of the relevant fields change. * * @param chatId - The ID of the chat to monitor * @returns The current status of the AI chat * * @example * ```tsx * import { useAiChatStatus } from "@liveblocks/react"; * * function ChatStatus() { * const { status, partType, toolName } = useAiChatStatus("my-chat"); * console.log(status); // "disconnected" | "loading" | "idle" | "generating" * console.log(status.partType); // "text" | "tool-invocation" | ... * console.log(status.toolName); // string | undefined * } * ``` */ declare function useAiChatStatus(chatId: string, /** @internal */ branchId?: MessageId): AiChatStatus; /** * Returns a function to send a message in an AI chat. * * @example * const sendAiMessage = useSendAiMessage("chat-id"); * sendAiMessage("Hello, Liveblocks AI!"); * * You can set options related to the message being sent, such as the copilot ID to use. * * @example * const sendAiMessage = useSendAiMessage("chat-id", { copilotId: "co_xxx" }); * sendAiMessage("Hello, Liveblocks AI!"); * * @example * const sendAiMessage = useSendAiMessage("chat-id", { copilotId: "co_xxx" }); * sendAiMessage({ text: "Hello, Liveblocks AI!", copilotId: "co_yyy" }); */ declare function useSendAiMessage(chatId: string, options?: UseSendAiMessageOptions): { (text: string): AiUserMessage; (options: SendAiMessageOptions): AiUserMessage; }; /** * Returns a function to send a message in an AI chat. * * @example * const sendAiMessage = useSendAiMessage(); * sendAiMessage({ chatId: "chat-id", text: "Hello, Liveblocks AI!" }); * * You can set options related to the message being sent, such as the copilot ID to use. * * @example * const sendAiMessage = useSendAiMessage(); * sendAiMessage({ chatId: "chat-id", text: "Hello, Liveblocks AI!", copilotId: "co_xxx" }); */ declare function useSendAiMessage(): (options: WithRequired) => AiUserMessage; /** * Sets up a client for connecting to Liveblocks, and is the recommended way to do * this for React apps. You must define either `authEndpoint` or `publicApiKey`. * Resolver functions should be placed inside here, and a number of other options * are available, which correspond with those passed to `createClient`. * Unlike `RoomProvider`, `LiveblocksProvider` doesn’t call Liveblocks servers when mounted, * and it should be placed higher in your app’s component tree. */ declare function LiveblocksProvider(props: PropsWithChildren>): react_jsx_runtime.JSX.Element; /** * Creates a LiveblocksProvider and a set of typed hooks. Note that any * LiveblocksProvider created in this way takes no props, because it uses * settings from the given client instead. */ declare function createLiveblocksContext(client: OpaqueClient): LiveblocksContextBundle; /** * Returns the inbox notifications for the current user. * * @example * const { inboxNotifications, error, isLoading } = useInboxNotifications(); */ declare function useInboxNotifications(options?: UseInboxNotificationsOptions): InboxNotificationsAsyncResult; /** * Returns the inbox notifications for the current user. * * @example * const { inboxNotifications } = useInboxNotifications(); */ declare function useInboxNotificationsSuspense(options?: UseInboxNotificationsOptions): { readonly isLoading: false; readonly inboxNotifications: _liveblocks_core.InboxNotificationData[]; readonly error?: undefined; hasFetchedAll: boolean; isFetchingMore: boolean; fetchMore: () => void; fetchMoreError?: Error | undefined; }; /** * Returns a function that marks all of the current user's inbox notifications as read. * * @example * const markAllInboxNotificationsAsRead = useMarkAllInboxNotificationsAsRead(); * markAllInboxNotificationsAsRead(); */ declare function useMarkAllInboxNotificationsAsRead(): () => void; /** * Returns a function that marks an inbox notification as read for the current user. * * @example * const markInboxNotificationAsRead = useMarkInboxNotificationAsRead(); * markInboxNotificationAsRead("in_xxx"); */ declare function useMarkInboxNotificationAsRead(): (inboxNotificationId: string) => void; /** * Returns a function that deletes all of the current user's inbox notifications. * * @example * const deleteAllInboxNotifications = useDeleteAllInboxNotifications(); * deleteAllInboxNotifications(); */ declare function useDeleteAllInboxNotifications(): () => void; /** * Returns a function that deletes an inbox notification for the current user. * * @example * const deleteInboxNotification = useDeleteInboxNotification(); * deleteInboxNotification("in_xxx"); */ declare function useDeleteInboxNotification(): (inboxNotificationId: string) => void; /** * Returns the number of unread inbox notifications for the current user. * * @example * const { count, error, isLoading } = useUnreadInboxNotificationsCount(); */ declare function useUnreadInboxNotificationsCount(options?: UseInboxNotificationsOptions): UnreadInboxNotificationsCountAsyncResult; /** * Returns the number of unread inbox notifications for the current user. * * @example * const { count } = useUnreadInboxNotificationsCount(); */ declare function useUnreadInboxNotificationsCountSuspense(options?: UseInboxNotificationsOptions): { readonly isLoading: false; readonly count: number; readonly error?: undefined; }; /** * Returns notification settings for the current user. * * @example * const [{ settings }, updateNotificationSettings] = useNotificationSettings() */ declare function useNotificationSettings(): [NotificationSettingsAsyncResult, (settings: PartialNotificationSettings) => void]; /** * Returns notification settings for the current user. * * @example * const [{ settings }, updateNotificationSettings] = useNotificationSettings() */ declare function useNotificationSettingsSuspense(): [{ readonly isLoading: false; readonly settings: _liveblocks_core.NotificationSettings; readonly error?: undefined; }, (settings: PartialNotificationSettings) => void]; /** * Returns a function that updates the user's notification * settings for a project. * * @example * const updateNotificationSettings = useUpdateNotificationSettings() */ declare function useUpdateNotificationSettings(): (settings: PartialNotificationSettings) => void; /** * Returns room info from a given room ID. * * @example * const { info, error, isLoading } = useRoomInfo("room-id"); */ declare function useRoomInfo(roomId: string): RoomInfoAsyncResult; /** * Returns room info from a given room ID. * * @example * const { info } = useRoomInfo("room-id"); */ declare function useRoomInfoSuspense(roomId: string): RoomInfoAsyncSuccess; /** * Returns group info from a given group ID. * * @example * const { info, error, isLoading } = useGroupInfo("group-id"); */ declare function useGroupInfo(groupId: string): GroupInfoAsyncResult; /** * Returns group info from a given group ID. * * @example * const { info } = useGroupInfo("group-id"); */ declare function useGroupInfoSuspense(groupId: string): GroupInfoAsyncSuccess; type TypedBundle$1 = LiveblocksContextBundle; /** * Returns the thread associated with a `"thread"` inbox notification. * * It can **only** be called with IDs of `"thread"` inbox notifications, * so we recommend only using it when customizing the rendering or in other * situations where you can guarantee the kind of the notification. * * When `useInboxNotifications` returns `"thread"` inbox notifications, * it also receives the associated threads and caches them behind the scenes. * When you call `useInboxNotificationThread`, it simply returns the cached thread * for the inbox notification ID you passed to it, without any fetching or waterfalls. * * @example * const thread = useInboxNotificationThread("in_xxx"); */ declare const _useInboxNotificationThread: TypedBundle$1["useInboxNotificationThread"]; /** * Returns user info from a given user ID. * * @example * const { user, error, isLoading } = useUser("user-id"); */ declare const _useUser: TypedBundle$1["useUser"]; /** * Returns user info from a given user ID. * * @example * const { user } = useUser("user-id"); */ declare const _useUserSuspense: TypedBundle$1["suspense"]["useUser"]; /** * @experimental * * This hook is experimental and could be removed or changed at any time! * Do not use unless explicitly recommended by the Liveblocks team. * * WARNING: * Please note that this hook currently returns all threads by most recently * updated threads first. This is inconsistent with the default sort order of * the useThreads() hook, which returns them in chronological order (by * creation date). In the final version, we will make these hooks behave * consistently, so expect that in the final version, you'll have to explicitly * specify the sort order to be by most recently updated first somehow. * The final API for that is still TBD. */ declare const _useUserThreads_experimental: TypedBundle$1["useUserThreads_experimental"]; /** * @experimental * * This hook is experimental and could be removed or changed at any time! * Do not use unless explicitly recommended by the Liveblocks team. * * WARNING: * Please note that this hook currently returns all threads by most recently * updated threads first. This is inconsistent with the default sort order of * the useThreads() hook, which returns them in chronological order (by * creation date). In the final version, we will make these hooks behave * consistently, so expect that in the final version, you'll have to explicitly * specify the sort order to be by most recently updated first somehow. * The final API for that is still TBD. */ declare const _useUserThreadsSuspense_experimental: TypedBundle$1["suspense"]["useUserThreads_experimental"]; /** * (Private beta) Returns the chats for the current user. * * @example * const { chats, error, isLoading } = useAiChats(); */ declare const _useAiChats: TypedBundle$1["useAiChats"]; /** * (Private beta) Returns the chats for the current user. * * @example * const { chats, error, isLoading } = useAiChats(); */ declare const _useAiChatsSuspense: TypedBundle$1["suspense"]["useAiChats"]; /** * (Private beta) Returns the information of the given chat. * * @example * const { chat, error, isLoading } = useAiChat("my-chat"); */ declare const _useAiChat: TypedBundle$1["useAiChat"]; /** * (Private beta) Returns the information of the given chat. * * @example * const { chat, error, isLoading } = useAiChat("my-chat"); */ declare const _useAiChatSuspense: TypedBundle$1["suspense"]["useAiChat"]; /** * (Private beta) Returns the messages in the given chat. * * @example * const { messages, error, isLoading } = useAiChatMessages("my-chat"); */ declare const _useAiChatMessages: TypedBundle$1["useAiChatMessages"]; /** * (Private beta) Returns the messages in the given chat. * * @example * const { messages, error, isLoading } = useAiChatMessages("my-chat"); */ declare const _useAiChatMessagesSuspense: TypedBundle$1["suspense"]["useAiChatMessages"]; /** * Returns metadata for a given URL. * * @example * const { metadata, error, isLoading } = useUrlMetadata("https://liveblocks.io"); */ declare const _useUrlMetadata: TypedBundle$1["useUrlMetadata"]; /** * Returns metadata for a given URL. * * @example * const { metadata } = useUrlMetadata("https://liveblocks.io"); */ declare const _useUrlMetadataSuspense: TypedBundle$1["suspense"]["useUrlMetadata"]; /** * Returns the current Liveblocks sync status, and triggers a re-render * whenever it changes. Can be used to render a "Saving..." indicator, or for * preventing that a browser tab can be closed until all changes have been * synchronized with the server. * * @example * const syncStatus = useSyncStatus(); // "synchronizing" | "synchronized" * const syncStatus = useSyncStatus({ smooth: true }); */ declare function useSyncStatus(options?: UseSyncStatusOptions): SyncStatus; /** * useErrorListener is a React hook that allows you to respond to any * Liveblocks error, for example room connection errors, errors * creating/editing/deleting threads, etc. * * @example * useErrorListener(err => { * console.error(err); * }) */ declare function useErrorListener(callback: (err: LiveblocksError) => void): void; /** * Returns the current connection status for the Room, and triggers * a re-render whenever it changes. Can be used to render a status badge. */ declare function useStatus(): Status; /** @private - Internal API, do not rely on it. */ declare function useReportTextEditor(editor: TextEditorType, rootKey: string): void; /** @private - Internal API, do not rely on it. */ declare function useYjsProvider(): IYjsProvider | undefined; /** @private - Internal API, do not rely on it. */ declare function useCreateTextMention(): (mentionId: string, mention: MentionData) => void; /** @private - Internal API, do not rely on it. */ declare function useDeleteTextMention(): (mentionId: string) => void; /** @private - Internal API, do not rely on it. */ declare function useResolveMentionSuggestions(): ((args: _liveblocks_core.ResolveMentionSuggestionsArgs) => _liveblocks_core.Awaitable) | undefined; /** @private - Internal API, do not rely on it. */ declare function useMentionSuggestionsCache(): Map; /** * Get informed when reconnecting to the Liveblocks servers is taking * longer than usual. This typically is a sign of a client that has lost * internet connectivity. * * This isn't problematic (because the Liveblocks client is still trying to * reconnect), but it's typically a good idea to inform users about it if * the connection takes too long to recover. * * @example * useLostConnectionListener(event => { * if (event === 'lost') { * toast.warn('Reconnecting to the Liveblocks servers is taking longer than usual...') * } else if (event === 'failed') { * toast.warn('Reconnecting to the Liveblocks servers failed.') * } else if (event === 'restored') { * toast.clear(); * } * }) */ declare function useLostConnectionListener(callback: (event: LostConnectionEvent) => void): void; /** * Returns the room.history */ declare function useHistory(): History; /** * Returns a function that undoes the last operation executed by the current * client. It does not impact operations made by other clients. */ declare function useUndo(): () => void; /** * Returns a function that redoes the last operation executed by the current * client. It does not impact operations made by other clients. */ declare function useRedo(): () => void; /** * Returns whether there are any operations to undo. */ declare function useCanUndo(): boolean; /** * Returns whether there are any operations to redo. */ declare function useCanRedo(): boolean; /** * Returns an array of connection IDs. This matches the values you'll get by * using the `useOthers()` hook. * * Roughly equivalent to: * useOthers((others) => others.map(other => other.connectionId), shallow) * * This is useful in particular to implement efficiently rendering components * for each user in the room, e.g. cursors. * * @example * const ids = useOthersConnectionIds(); * // [2, 4, 7] */ declare function useOthersConnectionIds(): readonly number[]; /** * Returns a function that creates a new feed in the current room. * * @example * const createFeed = useCreateFeed(); * createFeed("feed-id", { metadata: { name: "My Feed" } }); */ declare function useCreateFeed(): (feedId: string, options?: { metadata?: FeedCreateMetadata$1; createdAt?: number; }) => Promise; /** * Returns a function that deletes a feed from the current room. * * @example * const deleteFeed = useDeleteFeed(); * deleteFeed("feed-id"); */ declare function useDeleteFeed(): (feedId: string) => Promise; /** * Returns a function that updates a feed's metadata in the current room. * * @example * const updateFeedMetadata = useUpdateFeedMetadata(); * updateFeedMetadata("feed-id", { name: "Updated Name" }); */ declare function useUpdateFeedMetadata(): (feedId: string, metadata: FeedUpdateMetadata$1) => Promise; /** * Returns a function that adds a message to a feed in the current room. * * @example * const createFeedMessage = useCreateFeedMessage(); * createFeedMessage("feed-id", { text: "Hello" }); */ declare function useCreateFeedMessage(): (feedId: string, data: JsonObject, options?: { id?: string; createdAt?: number; }) => Promise; /** * Returns a function that deletes a message from a feed in the current room. * * @example * const deleteFeedMessage = useDeleteFeedMessage(); * deleteFeedMessage("feed-id", "message-id"); */ declare function useDeleteFeedMessage(): (feedId: string, messageId: string) => Promise; /** * Returns a function that updates a feed message in the current room. * * @example * const updateFeedMessage = useUpdateFeedMessage(); * updateFeedMessage("feed-id", "message-id", { text: "Updated" }); */ declare function useUpdateFeedMessage(): (feedId: string, messageId: string, data: JsonObject, options?: { updatedAt?: number; }) => Promise; /** * @private */ declare function useCreateRoomThread(roomId: string): (options: CreateThreadOptions) => ThreadData$1; declare function useDeleteRoomThread(roomId: string): (threadId: string) => void; declare function useEditRoomThreadMetadata(roomId: string): (options: EditThreadMetadataOptions) => void; /** * @private */ declare function useCreateRoomComment(roomId: string): (options: CreateCommentOptions) => CommentData$1; /** * @private */ declare function useEditRoomComment(roomId: string): (options: EditCommentOptions) => void; /** * Returns a function that deletes a comment. * If it is the last non-deleted comment, the thread also gets deleted. * * @example * const deleteComment = useDeleteComment(); * deleteComment({ threadId: "th_xxx", commentId: "cm_xxx" }) */ declare function useDeleteComment(): ({ threadId, commentId }: DeleteCommentOptions) => void; /** * @private */ declare function useDeleteRoomComment(roomId: string): ({ threadId, commentId }: DeleteCommentOptions) => void; /** * @private */ declare function useAddRoomCommentReaction(roomId: string): ({ threadId, commentId, emoji }: CommentReactionOptions) => void; /** * Returns a function that removes a reaction on a comment. * * @example * const removeReaction = useRemoveReaction(); * removeReaction({ threadId: "th_xxx", commentId: "cm_xxx", emoji: "👍" }) */ declare function useRemoveReaction(): ({ threadId, commentId, emoji }: CommentReactionOptions) => void; /** * @private */ declare function useRemoveRoomCommentReaction(roomId: string): ({ threadId, commentId, emoji }: CommentReactionOptions) => void; /** * @private */ declare function useMarkRoomThreadAsRead(roomId: string): (threadId: string) => void; /** * Returns a function that marks a thread as read. * * @example * const markThreadAsRead = useMarkThreadAsRead(); * markThreadAsRead("th_xxx"); */ declare function useMarkThreadAsRead(): (threadId: string) => void; /** * Returns a function that marks a thread as resolved. * * @example * const markThreadAsResolved = useMarkThreadAsResolved(); * markThreadAsResolved("th_xxx"); */ declare function useMarkThreadAsResolved(): (threadId: string) => void; /** * @private */ declare function useMarkRoomThreadAsResolved(roomId: string): (threadId: string) => void; /** * Returns a function that marks a thread as unresolved. * * @example * const markThreadAsUnresolved = useMarkThreadAsUnresolved(); * markThreadAsUnresolved("th_xxx"); */ declare function useMarkThreadAsUnresolved(): (threadId: string) => void; /** * @private */ declare function useMarkRoomThreadAsUnresolved(roomId: string): (threadId: string) => void; /** * Returns a function that subscribes the user to a thread. * * @example * const subscribeToThread = useSubscribeToThread(); * subscribeToThread("th_xxx"); */ declare function useSubscribeToThread(): (threadId: string) => void; /** * Returns a function that unsubscribes the user from a thread. * * @example * const unsubscribeFromThread = useUnsubscribeFromThread(); * unsubscribeFromThread("th_xxx"); */ declare function useUnsubscribeFromThread(): (threadId: string) => void; /** * Returns the subscription status of a thread, methods to update it, and when * the thread was last read. * * @example * const { status, subscribe, unsubscribe, unreadSince } = useThreadSubscription("th_xxx"); */ declare function useThreadSubscription(threadId: string): ThreadSubscription; /** * @private */ declare function useRoomThreadSubscription(roomId: string, threadId: string): ThreadSubscription; /** * Returns the version data bianry for a given version * * @example * const {data} = useHistoryVersionData(versionId); */ declare function useHistoryVersionData(versionId: string): HistoryVersionDataAsyncResult; /** * Returns a function that updates the user's subscription settings * for the current room. * * @example * const updateRoomSubscriptionSettings = useUpdateRoomSubscriptionSettings(); * updateRoomSubscriptionSettings({ threads: "all" }); */ declare function useUpdateRoomSubscriptionSettings(): (settings: Partial) => void; /** * @private For internal use only. Do not rely on this hook. */ declare function useSuspendUntilPresenceReady(): void; /** * Returns an array of connection IDs. This matches the values you'll get by * using the `useOthers()` hook. * * Roughly equivalent to: * useOthers((others) => others.map(other => other.connectionId), shallow) * * This is useful in particular to implement efficiently rendering components * for each user in the room, e.g. cursors. * * @example * const ids = useOthersConnectionIds(); * // [2, 4, 7] */ declare function useOthersConnectionIdsSuspense(): readonly number[]; /** * @private For internal use only. Do not rely on this hook. */ declare function useSuspendUntilStorageReady(): void; /** * Returns a presigned URL for an attachment by its ID. * * @example * const { url, error, isLoading } = useAttachmentUrl("at_xxx"); */ declare function useAttachmentUrl(attachmentId: string): AttachmentUrlAsyncResult; /** * @private For internal use only. Do not rely on this hook. Use `useAttachmentUrl` instead. */ declare function useRoomAttachmentUrl(attachmentId: string, roomId: string): AttachmentUrlAsyncResult; /** * Returns a presigned URL for an attachment by its ID. * * @example * const { url } = useAttachmentUrl("at_xxx"); */ declare function useAttachmentUrlSuspense(attachmentId: string): { readonly isLoading: false; readonly url: string; readonly error: undefined; }; /** * @private For internal use only. Do not rely on this hook. */ declare function useRoomPermissions(roomId: string): Set<_liveblocks_core.Permission>; /** * Creates a RoomProvider and a set of typed hooks to use in your app. Note * that any RoomProvider created in this way does not need to be nested in * LiveblocksProvider, as it already has access to the client. */ declare function createRoomContext

(client: OpaqueClient): RoomContextBundle; type TypedBundle = RoomContextBundle; /** * Makes a Room available in the component hierarchy below. * Joins the room when the component is mounted, and automatically leaves * the room when the component is unmounted. */ declare const _RoomProvider: TypedBundle["RoomProvider"]; /** * Returns a callback that lets you broadcast custom events to other users in the room * * @example * const broadcast = useBroadcastEvent(); * * broadcast({ type: "CUSTOM_EVENT", data: { x: 0, y: 0 } }); */ declare const _useBroadcastEvent: TypedBundle["useBroadcastEvent"]; /** * Get informed when users enter or leave the room, as an event. * * @example * useOthersListener({ type, user, others }) => { * if (type === 'enter') { * // `user` has joined the room * } else if (type === 'leave') { * // `user` has left the room * } * }) */ declare const _useOthersListener: TypedBundle["useOthersListener"]; /** * Returns the Room of the nearest RoomProvider above in the React component * tree. */ declare const _useRoom: TypedBundle["useRoom"]; /** * Returns whether the hook is called within a RoomProvider context. * * @example * const isInsideRoom = useIsInsideRoom(); */ declare const _useIsInsideRoom: TypedBundle["useIsInsideRoom"]; /** * Returns a function that adds a reaction from a comment. * * @example * const addReaction = useAddReaction(); * addReaction({ threadId: "th_xxx", commentId: "cm_xxx", emoji: "👍" }) */ declare const _useAddReaction: TypedBundle["useAddReaction"]; /** * Create a callback function that lets you mutate Liveblocks state. * * The first argument that gets passed into your callback will be * a "mutation context", which exposes the following: * * - `storage` - The mutable Storage root. * You can mutate any Live structures with this, for example: * `storage.get('layers').get('layer1').set('fill', 'red')` * * - `setMyPresence` - Call this with a new (partial) Presence value. * * - `self` - A read-only version of the latest self, if you need it to * compute the next state. * * - `others` - A read-only version of the latest others list, if you * need it to compute the next state. * * useMutation is like React's useCallback, except that the first argument * that gets passed into your callback will be a "mutation context". * * If you want get access to the immutable root somewhere in your mutation, * you can use `storage.toJSON()`. * * @example * const fillLayers = useMutation( * ({ storage }, color: Color) => { * ... * }, * [], * ); * * fillLayers('red'); * * const deleteLayers = useMutation( * ({ storage }) => { * ... * }, * [], * ); * * deleteLayers(); */ declare const _useMutation: TypedBundle["useMutation"]; /** * Returns a function that creates a thread with an initial comment, and optionally some metadata. * * @example * const createThread = useCreateThread(); * createThread({ body: {}, metadata: {} }); */ declare const _useCreateThread: TypedBundle["useCreateThread"]; /** * Returns a function that deletes a thread and its associated comments. * Only the thread creator can delete a thread, it will throw otherwise. * * @example * const deleteThread = useDeleteThread(); * deleteThread("th_xxx"); */ declare const _useDeleteThread: TypedBundle["useDeleteThread"]; /** * Returns a function that edits a thread's metadata. * To delete an existing metadata property, set its value to `null`. * * @example * const editThreadMetadata = useEditThreadMetadata(); * editThreadMetadata({ threadId: "th_xxx", metadata: {} }) */ declare const _useEditThreadMetadata: TypedBundle["useEditThreadMetadata"]; /** * Returns a function that adds a comment to a thread. * * @example * const createComment = useCreateComment(); * createComment({ threadId: "th_xxx", body: {} }); */ declare const _useCreateComment: TypedBundle["useCreateComment"]; /** * Returns a function that edits a comment. * * @example * const editComment = useEditComment() * editComment({ threadId: "th_xxx", commentId: "cm_xxx", body: {} }) */ declare const _useEditComment: TypedBundle["useEditComment"]; /** * Returns a function that edits a comment's metadata. * To delete an existing metadata property, set its value to `null`. * * @example * const editCommentMetadata = useEditCommentMetadata(); * editCommentMetadata({ threadId: "th_xxx", commentId: "cm_xxx", metadata: { tag: "important", externalId: 1234 } }) */ declare const _useEditCommentMetadata: TypedBundle["useEditCommentMetadata"]; /** * useEventListener is a React hook that allows you to respond to events broadcast * by other users in the room. * * The `user` argument will indicate which `User` instance sent the message. * This will be equal to one of the others in the room, but it can be `null` * in case this event was broadcasted from the server. * * @example * useEventListener(({ event, user, connectionId }) => { * // ^^^^ Will be Client A * if (event.type === "CUSTOM_EVENT") { * // Do something * } * }); */ declare const _useEventListener: TypedBundle["useEventListener"]; /** * Returns the presence of the current user of the current room, and a function to update it. * It is different from the setState function returned by the useState hook from * You don't need to pass the full presence object to update it. * * @example * const [myPresence, updateMyPresence] = useMyPresence(); * updateMyPresence({ x: 0 }); * updateMyPresence({ y: 0 }); * * // At the next render, "myPresence" will be equal to "{ x: 0, y: 0 }" */ declare const _useMyPresence: TypedBundle["useMyPresence"]; /** * Related to useOthers(), but optimized for selecting only "subsets" of * others. This is useful for performance reasons in particular, because * selecting only a subset of users also means limiting the number of * re-renders that will be triggered. * * @example * const avatars = useOthersMapped(user => user.info.avatar); * // ^^^^^^^ * // { connectionId: number; data: string }[] * * The selector function you pass to useOthersMapped() is called an "item * selector", and operates on a single user at a time. If you provide an * (optional) "item comparison" function, it will be used to compare each * item pairwise. * * For example, to select multiple properties: * * @example * const avatarsAndCursors = useOthersMapped( * user => [u.info.avatar, u.presence.cursor], * shallow, // 👈 * ); */ declare const _useOthersMapped: TypedBundle["useOthersMapped"]; /** * Related to useOthers(), but optimized for selecting only "subsets" of * others. This is useful for performance reasons in particular, because * selecting only a subset of users also means limiting the number of * re-renders that will be triggered. * * @example * const avatars = useOthersMapped(user => user.info.avatar); * // ^^^^^^^ * // { connectionId: number; data: string }[] * * The selector function you pass to useOthersMapped() is called an "item * selector", and operates on a single user at a time. If you provide an * (optional) "item comparison" function, it will be used to compare each * item pairwise. * * For example, to select multiple properties: * * @example * const avatarsAndCursors = useOthersMapped( * user => [u.info.avatar, u.presence.cursor], * shallow, // 👈 * ); */ declare const _useOthersMappedSuspense: TypedBundle["suspense"]["useOthersMapped"]; /** * Returns the threads within the current room. * * @example * const { threads, error, isLoading } = useThreads(); */ declare const _useThreads: TypedBundle["useThreads"]; /** * Returns feeds for the current room. * * @example * const { feeds, error, isLoading } = useFeeds(); */ declare const _useFeeds: TypedBundle["useFeeds"]; /** * Returns messages for a specific feed in the current room. * * @example * const { messages, error, isLoading } = useFeedMessages("feed-id"); */ declare const _useFeedMessages: TypedBundle["useFeedMessages"]; /** * Returns feeds for the current room. * * @example * const { feeds } = useFeeds(); */ declare const _useFeedsSuspense: TypedBundle["suspense"]["useFeeds"]; /** * Returns messages for a specific feed in the current room. * * @example * const { messages } = useFeedMessages("feed-id"); */ declare const _useFeedMessagesSuspense: TypedBundle["suspense"]["useFeedMessages"]; /** * Returns the result of searching comments by text in the current room. The result includes the id and the plain text content of the matched comments along with the parent thread id of the comment. * * @example * const { results, error, isLoading } = useSearchComments({ query: { text: "hello"} }); */ declare const _useSearchComments: TypedBundle["useSearchComments"]; /** * Returns the threads within the current room. * * @example * const { threads } = useThreads(); */ declare const _useThreadsSuspense: TypedBundle["suspense"]["useThreads"]; /** * Returns the user's subscription settings for the current room * and a function to update them. * * @example * const [{ settings }, updateSettings] = useRoomSubscriptionSettings(); */ declare const _useRoomSubscriptionSettings: TypedBundle["useRoomSubscriptionSettings"]; /** * Returns the user's subscription settings for the current room * and a function to update them. * * @example * const [{ settings }, updateSettings] = useRoomSubscriptionSettings(); */ declare const _useRoomSubscriptionSettingsSuspense: TypedBundle["suspense"]["useRoomSubscriptionSettings"]; /** * (Private beta) Returns a history of versions of the current room. * * @example * const { versions, error, isLoading } = useHistoryVersions(); */ declare const _useHistoryVersions: TypedBundle["useHistoryVersions"]; /** * (Private beta) Returns a history of versions of the current room. * * @example * const { versions } = useHistoryVersions(); */ declare const _useHistoryVersionsSuspense: TypedBundle["suspense"]["useHistoryVersions"]; /** * Given a connection ID (as obtained by using `useOthersConnectionIds`), you * can call this selector deep down in your component stack to only have the * component re-render if properties for this particular user change. * * @example * // Returns only the selected values re-renders whenever that selection changes) * const { x, y } = useOther(2, user => user.presence.cursor); */ declare const _useOther: TypedBundle["useOther"]; /** * Returns an array with information about all the users currently connected in * the room (except yourself). * * @example * const others = useOthers(); * * // Example to map all cursors in JSX * return ( * <> * {others.map((user) => { * if (user.presence.cursor == null) { * return null; * } * return * })} * * ) */ declare function _useOthers(): readonly User[]; /** * Extract arbitrary data based on all the users currently connected in the * room (except yourself). * * The selector function will get re-evaluated any time a user enters or * leaves the room, as well as whenever their presence data changes. * * The component that uses this hook will automatically re-render if your * selector function returns a different value from its previous run. * * By default `useOthers()` uses strict `===` to check for equality. Take * extra care when returning a computed object or list, for example when you * return the result of a .map() or .filter() call from the selector. In * those cases, you'll probably want to use a `shallow` comparison check. * * @example * const avatars = useOthers(users => users.map(u => u.info.avatar), shallow); * const cursors = useOthers(users => users.map(u => u.presence.cursor), shallow); * const someoneIsTyping = useOthers(users => users.some(u => u.presence.isTyping)); * */ declare function _useOthers(selector: (others: readonly User[]) => T, isEqual?: (prev: T, curr: T) => boolean): T; /** * Given a connection ID (as obtained by using `useOthersConnectionIds`), you * can call this selector deep down in your component stack to only have the * component re-render if properties for this particular user change. * * @example * // Returns only the selected values re-renders whenever that selection changes) * const { x, y } = useOther(2, user => user.presence.cursor); */ declare const _useOtherSuspense: TypedBundle["suspense"]["useOther"]; /** * Returns an array with information about all the users currently connected in * the room (except yourself). * * @example * const others = useOthers(); * * // Example to map all cursors in JSX * return ( * <> * {others.map((user) => { * if (user.presence.cursor == null) { * return null; * } * return * })} * * ) */ declare function _useOthersSuspense(): readonly User[]; /** * Extract arbitrary data based on all the users currently connected in the * room (except yourself). * * The selector function will get re-evaluated any time a user enters or * leaves the room, as well as whenever their presence data changes. * * The component that uses this hook will automatically re-render if your * selector function returns a different value from its previous run. * * By default `useOthers()` uses strict `===` to check for equality. Take * extra care when returning a computed object or list, for example when you * return the result of a .map() or .filter() call from the selector. In * those cases, you'll probably want to use a `shallow` comparison check. * * @example * const avatars = useOthers(users => users.map(u => u.info.avatar), shallow); * const cursors = useOthers(users => users.map(u => u.presence.cursor), shallow); * const someoneIsTyping = useOthers(users => users.some(u => u.presence.isTyping)); * */ declare function _useOthersSuspense(selector: (others: readonly User[]) => T, isEqual?: (prev: T, curr: T) => boolean): T; /** * Extract arbitrary data from the Liveblocks Storage state, using an * arbitrary selector function. * * The selector function will get re-evaluated any time something changes in * Storage. The value returned by your selector function will also be the * value returned by the hook. * * The `root` value that gets passed to your selector function is * a immutable/readonly version of your Liveblocks storage root. * * The component that uses this hook will automatically re-render if the * returned value changes. * * By default `useStorage()` uses strict `===` to check for equality. Take * extra care when returning a computed object or list, for example when you * return the result of a .map() or .filter() call from the selector. In * those cases, you'll probably want to use a `shallow` comparison check. */ declare const _useStorage: TypedBundle["useStorage"]; /** * Extract arbitrary data from the Liveblocks Storage state, using an * arbitrary selector function. * * The selector function will get re-evaluated any time something changes in * Storage. The value returned by your selector function will also be the * value returned by the hook. * * The `root` value that gets passed to your selector function is * a immutable/readonly version of your Liveblocks storage root. * * The component that uses this hook will automatically re-render if the * returned value changes. * * By default `useStorage()` uses strict `===` to check for equality. Take * extra care when returning a computed object or list, for example when you * return the result of a .map() or .filter() call from the selector. In * those cases, you'll probably want to use a `shallow` comparison check. */ declare const _useStorageSuspense: TypedBundle["suspense"]["useStorage"]; /** * Gets the current user once it is connected to the room. * * @example * const me = useSelf(); * if (me !== null) { * const { x, y } = me.presence.cursor; * } */ declare function _useSelf(): User | null; /** * Extract arbitrary data based on the current user. * * The selector function will get re-evaluated any time your presence data * changes. * * The component that uses this hook will automatically re-render if your * selector function returns a different value from its previous run. * * By default `useSelf()` uses strict `===` to check for equality. Take extra * care when returning a computed object or list, for example when you return * the result of a .map() or .filter() call from the selector. In those * cases, you'll probably want to use a `shallow` comparison check. * * Will return `null` while Liveblocks isn't connected to a room yet. * * @example * const cursor = useSelf(me => me.presence.cursor); * if (cursor !== null) { * const { x, y } = cursor; * } * */ declare function _useSelf(selector: (me: User) => T, isEqual?: (prev: T, curr: T) => boolean): T | null; /** * Gets the current user once it is connected to the room. * * @example * const me = useSelf(); * const { x, y } = me.presence.cursor; */ declare function _useSelfSuspense(): User; /** * Extract arbitrary data based on the current user. * * The selector function will get re-evaluated any time your presence data * changes. * * The component that uses this hook will automatically re-render if your * selector function returns a different value from its previous run. * * By default `useSelf()` uses strict `===` to check for equality. Take extra * care when returning a computed object or list, for example when you return * the result of a .map() or .filter() call from the selector. In those * cases, you'll probably want to use a `shallow` comparison check. * * @example * const cursor = useSelf(me => me.presence.cursor); * const { x, y } = cursor; * */ declare function _useSelfSuspense(selector: (me: User) => T, isEqual?: (prev: T, curr: T) => boolean): T; /** * Returns the mutable (!) Storage root. This hook exists for * backward-compatible reasons. * * @example * const [root] = useStorageRoot(); */ declare const _useStorageRoot: TypedBundle["useStorageRoot"]; /** * useUpdateMyPresence is similar to useMyPresence but it only returns the function to update the current user presence. * 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. * * @example * const updateMyPresence = useUpdateMyPresence(); * updateMyPresence({ x: 0 }); * updateMyPresence({ y: 0 }); * * // At the next render, the presence of the current user will be equal to "{ x: 0, y: 0 }" */ declare const _useUpdateMyPresence: TypedBundle["useUpdateMyPresence"]; export { useDeleteAiChat as $, type AiChatStatus as A, type UseThreadsOptions as B, ClientContext as C, createLiveblocksContext as D, createRoomContext as E, _useAddReaction as F, type GroupAsyncResult as G, _useAiChat as H, _useAiChatMessages as I, useAiChatStatus as J, _useAiChats as K, LiveblocksProvider as L, type MutationContext as M, useAttachmentUrl as N, _useBroadcastEvent as O, useCanRedo as P, useCanUndo as Q, type RegisterAiKnowledgeProps as R, type SendAiMessageOptions as S, useClient as T, type UseSendAiMessageOptions as U, useCreateAiChat as V, _useCreateComment as W, useCreateFeed as X, useCreateFeedMessage as Y, _useCreateThread as Z, _RoomProvider as _, useClientOrNull as a, useAttachmentUrlSuspense as a$, useDeleteAllInboxNotifications as a0, useDeleteComment as a1, useDeleteFeed as a2, useDeleteFeedMessage as a3, useDeleteInboxNotification as a4, _useDeleteThread as a5, _useEditComment as a6, _useEditCommentMetadata as a7, _useEditThreadMetadata as a8, useErrorListener as a9, _useRoom as aA, useRoomInfo as aB, _useRoomSubscriptionSettings as aC, _useSearchComments as aD, _useSelf as aE, useSendAiMessage as aF, useStatus as aG, _useStorage as aH, _useStorageRoot as aI, useSubscribeToThread as aJ, useSyncStatus as aK, useThreadSubscription as aL, _useThreads as aM, useUndo as aN, useUnreadInboxNotificationsCount as aO, useUnsubscribeFromThread as aP, useUpdateFeedMessage as aQ, useUpdateFeedMetadata as aR, _useUpdateMyPresence as aS, useUpdateNotificationSettings as aT, useUpdateRoomSubscriptionSettings as aU, _useUrlMetadata as aV, _useUser as aW, _useUserThreads_experimental as aX, _useAiChatSuspense as aY, _useAiChatMessagesSuspense as aZ, _useAiChatsSuspense as a_, _useEventListener as aa, _useFeedMessages as ab, _useFeeds as ac, useGroupInfo as ad, useHistory as ae, useHistoryVersionData as af, _useHistoryVersions as ag, _useInboxNotificationThread as ah, useInboxNotifications as ai, _useIsInsideRoom as aj, useLostConnectionListener as ak, useMarkAllInboxNotificationsAsRead as al, useMarkInboxNotificationAsRead as am, useMarkThreadAsRead as an, useMarkThreadAsResolved as ao, useMarkThreadAsUnresolved as ap, _useMutation as aq, _useMyPresence as ar, useNotificationSettings as as, _useOther as at, _useOthers as au, useOthersConnectionIds as av, _useOthersListener as aw, _useOthersMapped as ax, useRedo as ay, useRemoveReaction as az, useCreateRoomComment as b, _useFeedMessagesSuspense as b0, _useFeedsSuspense as b1, useGroupInfoSuspense as b2, _useHistoryVersionsSuspense as b3, useInboxNotificationsSuspense as b4, useNotificationSettingsSuspense as b5, _useOtherSuspense as b6, _useOthersSuspense as b7, useOthersConnectionIdsSuspense as b8, _useOthersMappedSuspense as b9, useRoomInfoSuspense as ba, _useRoomSubscriptionSettingsSuspense as bb, _useSelfSuspense as bc, _useStorageSuspense as bd, _useThreadsSuspense as be, useUnreadInboxNotificationsCountSuspense as bf, _useUrlMetadataSuspense as bg, _useUserSuspense as bh, _useUserThreadsSuspense_experimental as bi, useCreateRoomThread as c, useCreateTextMention as d, useDeleteRoomComment as e, useDeleteRoomThread as f, getUmbrellaStoreForClient as g, useDeleteTextMention as h, useEditRoomComment as i, useEditRoomThreadMetadata as j, useMarkRoomThreadAsRead as k, useMarkRoomThreadAsResolved as l, useMarkRoomThreadAsUnresolved as m, useMentionSuggestionsCache as n, useRemoveRoomCommentReaction as o, useReportTextEditor as p, useResolveMentionSuggestions as q, useRoomAttachmentUrl as r, useRoomPermissions as s, useRoomThreadSubscription as t, useAddRoomCommentReaction as u, useSuspendUntilPresenceReady as v, useSuspendUntilStorageReady as w, useYjsProvider as x, type RegisterAiToolProps as y, GlobalRoomContext as z };