talkjs
Version:
Build the perfect messaging experience in 10 minutes.
1,275 lines (1,242 loc) • 245 kB
TypeScript
/**
* A node in a {@link TextBlock} that renders its children as a clickable {@link https://talkjs.com/docs/Features/Customizations/Action_Buttons_Links/ | action button} which triggers a custom action.
*
* @remarks
* By default, users do not have permission to send messages containing action buttons as they can be used maliciously to trick others into invoking custom actions.
* For example, a user could send an "accept offer" action button, but disguise it as "view offer".
*
* @public
*/
export declare interface ActionButtonNode {
type: "actionButton";
/**
* The name of the custom action to invoke when the button is clicked.
*/
action: string;
/**
* The parameters to pass to the custom action when the button is clicked.
*/
params: Record<string, string>;
children: TextNode[];
}
/**
* @public
* Provides additional parameters to custom message action or conversation action events.
*/
export declare interface ActionEventParams {
/**
* Any number of key/value pairs that will be sent with the action event.
*
* @remarks
* Both the key and the value must be strings. Deeply nested JSON is not supported.
*
* Add to action buttons in your theme components with the syntax `data-<key>=<value>`,
* or to action buttons in messages with the syntax `action?<key>=<value>`.
*
* @example In a theme
* ```
* <ActionButton action="color" data-choice="red">Red</ActionButton>
* ```
*
* This theme component creates an action button that emits a `color` action event
* when you click it, with a parameter called `choice` that takes the value `red`.
*
* @example In message markup
* ```
* <actionbutton:color?choice=blue|Blue>
* ```
*
* This message markup creates an action button that emits a `color` message action event
* when you click it, with a parameter called `choice` that takes the value `blue`.
*/
[key: string]: string;
}
/**
* A node in a {@link TextBlock} that renders its children as a clickable {@link https://talkjs.com/docs/Features/Customizations/Action_Buttons_Links/ | action link} which triggers a custom action.
*
* @remarks
* By default, users do not have permission to send messages containing `ActionLinkNode` as it can be used maliciously to trick others into invoking custom actions.
* For example, a user could send an "accept offer" action link, but disguise it as a link to a website.
*
* @public
*/
export declare interface ActionLinkNode {
type: "actionLink";
/**
* The name of the custom action to invoke when the link is clicked.
*/
action: string;
/**
* The parameters to pass to the custom action when the link is clicked.
*/
params: Record<string, string>;
children: TextNode[];
}
declare type Attachment = {
url: string;
size: number;
dimensions?: AttachmentDimensions;
};
declare type AttachmentDimensions = {
width?: number;
height?: number;
duration?: number;
};
/**
* A FileBlock variant for an audio attachment, with additional audio-specific metadata.
*
* @remarks
* You can identify this variant by checking for `subtype: "audio"`.
*
* The same file could be uploaded as either an audio block, or as a {@link VoiceBlock}.
* The same data will be available either way, but they will be rendered differently in the UI.
*
* Includes metadata about the duration of the audio file in seconds, where available.
*
* Audio files that you upload with the TalkJS UI will include the duration as long as the sender's browser can preview the file.
* Audio files that you upload with the REST API or {@link Session.uploadAudio} will include the duration if you specified it when uploading.
* Audio files attached in a reply to an email notification will not include the duration.
*
* @public
*/
export declare interface AudioBlock {
type: "file";
subtype: "audio";
/**
* An encoded identifier for this file. Use in {@link SendFileBlock} to send this file in another message.
*/
fileToken: FileToken;
/**
* The URL where you can fetch the file
*/
url: string;
/**
* The size of the file in bytes
*/
size: number;
/**
* The name of the audio file, including file extension
*/
filename: string;
/**
* The duration of the audio in seconds, if known
*/
duration?: number;
}
/**
* @public
*/
export declare interface AudioFileMetadata {
/**
* The name of the file including extension.
*/
filename: string;
/**
* The duration of the audio file in seconds, if known.
*/
duration?: number;
}
/**
* A node in a {@link TextBlock} that renders `text` as a link (HTML `<a>`).
*
* @remarks
* Used when user-typed text is turned into a link automatically.
*
* Unlike {@link LinkNode}, users do have permission to send AutoLinkNodes by default, because the `text` and `url` properties must match.
* Specifically:
*
* - If `text` is an email, `url` must contain a `mailto:` link to the same email address
*
* - If `text` is a phone number, `url` must contain a `tel:` link to the same phone number
*
* - If `text` is a website, the domain name including subdomains must be the same in both `text` and `url`.
* If `text` includes a protocol (such as `https`), path (/page), query string (?page=true), or url fragment (#title), they must be the same in `url`.
* If `text` does not specify a protocol, `url` must use either `https` or `http`.
*
* This means that the following AutoLink is valid:
*
* ```json
* {
* type: "autoLink",
* text: "talkjs.com"
* url: "https://talkjs.com/docs/Reference/JavaScript_Data_API/Message_Content/#AutoLinkNode"
* }
* ```
*
* That link will appear as `talkjs.com` and link you to the specific section of the documentation that explains how AutoLinkNodes work.
*
* These rules ensure that the user knows what link they are clicking, and prevents AutoLinkNode being used for phishing.
* If you try to send a message containing an AutoLink that breaks these rules, the request will be rejected.
*
* @public
*/
export declare interface AutoLinkNode {
type: "autoLink";
/**
* The URL to open when a user clicks this node.
*/
url: string;
/**
* The text to display in the link.
*/
text: string;
}
/**
* @public
* @hidden due to being empty
* @deprecated Use `chatbox.onBlur(() => {...})` instead, without an event parameter.
*/
export declare interface BlurEvent {
}
/**
* Sent by {@link Session.onBrowserPermissionDenied} when the user tried to do
* an action that require explicit browser permission, but it was denied.
*
* @public
*/
export declare interface BrowserPermissionDeniedEvent {
/**
* The type of permission that was denied.
*
* @remarks
* Note that more possible values may be added in the future, so make sure your
* handler can deal with unknown permission types gracefully.
*/
type: PermissionType;
}
/**
* Sent by {@link Session.onBrowserPermissionNeeded} when a browser permission
* dialog is about to be shown to the user.
*
* @public
*/
export declare interface BrowserPermissionNeededEvent {
/**
* The type of permission requested.
*
* @remarks
* Note that more possible values may be added in the future, so make sure your
* handler can deal with unknown permission types gracefully.
*/
type: PermissionType;
/**
* Cancel whatever user action caused the permission to be requested.
*
* @remarks
* For example, if a user wants to share their location for the first time so
* that this event is triggered, then if you call `preventDefault()`, no
* permission will be requested from the browser, the location sharing will be
* cancelled, and TalkJS will continue as if the location sharing button had
* not been clicked at all.
*
* This may be useful if you're using this event to show custom UI elements
* that nudge users towards granting permission, and this UI has a "cancel"
* button.
*/
preventDefault(): void;
}
/**
* A node in a {@link TextBlock} that adds indentation for a bullet-point list around its children (HTML `<ul>`).
*
* @remarks
* Used when users send a bullet-point list by starting lines of their message with `-` or `*`.
*
* @public
*/
export declare interface BulletListNode {
type: "bulletList";
children: TextNode[];
}
/**
* A node in a {@link TextBlock} that renders its children with a bullet-point (HTML `<li>`).
*
* @remarks
* Used when users start a line of their message with `-` or `*`.
*
* @public
*/
export declare interface BulletPointNode {
type: "bulletPoint";
children: TextNode[];
}
/**
* A messaging UI for just a single conversation
*
* @remarks
* There is no way for the user to switch between conversations
* (but you can change the active conversation through {@link Chatbox.select}).
* Create a Chatbox through {@link Session.createChatbox} and then call
* {@link Chatbox.mount} to show it.
* @public
*/
export declare interface Chatbox extends UIBox {
/**
* Renders the Chatbox UI inside a DOM element on your page.
*
* @remarks
* The container element specified by `container` must either be a DOM Element (as returned by e.g.
* `document.getElementById`) or a JQuery object with a single element.
*/
mount(container: HTMLElement | null): Promise<void>;
/**
* Destroys the chatbox and removes it from the DOM
*
* @remarks
* Destroys the chatbox, removes it from the DOM and removes all event listeners it has running. Call this before removing
* the chatbox container from the DOM.
*/
destroy(): void;
}
/**
* @alias UIBox Chatbox
* @public
*/
export declare interface ChatboxOptions {
/**
* Controls the text direction (for supporting right-to-left languages such as Arabic and Hebrew). TalkJS tries
* to determine the appropriate text direction from the parent page, but if that does not work or you want to
* explicitly control it, you can override it here. Defaults to "rtl".
*/
dir?: "rtl" | "ltr";
/**
* Sets the message input box to the given text.
* You can use this to suggest a certain initial message to be sent. The user can still edit it before hitting "send".
*
* @deprecated We recommend using {@link MessageField.setText} before mounting the chatbox to precisely control when message suggestions are shown.
*/
messageSuggestion?: string;
/**
* Used to control if the Chat Header is displayed in the UI. Defaults to true.
*/
showChatHeader?: boolean;
/**
* Controls what text appears in the chat title, in the header above the messages.
* Defaults to `"participants"`.
*
* (also see {@link ChatboxOptions.chatSubtitleMode} and {@link InboxOptions.feedConversationTitleMode})
*
* @deprecated This field only has effect if you use a {@link https://talkjs.com/docs/Features/Themes/Legacy_Themes_(limited_CSS)/ | Legacy Theme}, or an older custom theme which does not have a ChatHeader component. If you do not, edit the ChatHeader component in the theme editor instead.
*/
chatTitleMode?: "subject" | "participants";
/**
* Controls what text appears in the chat subtitle, right below the chat title.
* No subtitle is displayed when the conversation has no subject set or when set to `null`.
* Defaults to `"subject"`.
*
* (also see {@link ChatboxOptions.chatTitleMode} and {@link InboxOptions.feedConversationTitleMode})
*
* @deprecated This field only has effect if you use a {@link https://talkjs.com/docs/Features/Themes/Legacy_Themes_(limited_CSS)/ | Legacy Theme }, or an older custom theme which does not have a ChatHeader component. If you do not, edit the ChatHeader component in the theme editor instead.
*/
chatSubtitleMode?: "subject" | "participants" | null;
/**
* TalkJS leverages `iframe`s behind the scenes and therefore not all services that you use in your app will work out of the box.
* This option adds support for a number of services to help you use them. Let us know if you're missing any.
*/
thirdparties?: ThirdPartyOptions;
/**
* Used to control which messages are shown in the message list, depending on a type, origin
* or custom message attributes.
*
* *Note*: Messages are only filtered in the message list. The inbox UI's conversation feed will always show the last message sent to the conversation, regardless of the message filter set.
*
* See {@link MessagePredicate} for all available options.
*
* You can also modify the filter on the fly using {@link UIBox.setMessageFilter}.
*/
messageFilter?: MessagePredicate;
/**
* TalkJS can translate conversations to the current user's locale using Google Translate.
* This option specifies which conversations should be translated in this UI. You can pass a boolean to enable or turn off
* translation for all conversations, "auto" to enable translation on conversations where users have different locales,
* or you can pass an array of {@link ConversationBuilder}s or conversation Ids to be translated.
* This feature is only available on the Growth plan and above. Make sure you add your Google Translate API key on the "Settings" page of the dashboard.
*/
translateConversations?: boolean | "auto" | string[] | ConversationBuilder[];
/**
* Set this to `true` to show a translation toggle in all conversations.
* Set this to `"auto"` to show a translation toggle in conversations where there are participants with different locales.
* This setting defaults to `false`, meaning that no toggles will be shown.
* In order to use this, you must be on the Growth plan, and set a Google Translate API key on the "Settings" page of the dashboard.
*/
showTranslationToggle?: boolean | "auto";
/**
* Settings that affect the behavior of the message field
*/
messageField?: MessageFieldOptions;
/**
* Overrides the theme used for this chat UI.
*
* @remarks
* This only works with themes created in the Theme Editor. If you don't pass a theme name, we'll first check for a theme set in the user's role, and then fall back to using the default theme.
*
* You can either pass the name of the theme you'd like to use, or a {@link ThemeOptions} object, which you can use to pass variables to your theme.
*/
theme?: string | ThemeOptions;
/**
* Enables capturing {@link Chatbox.onKeyup} events.
*
* @remarks
* Note: Setting this to true also disables any non-standard keyboard shortcuts in TalkJS.
*
* At the time of writing, the only such shortcut is that when `captureKeyboardEvents` is
* disabled, TalkJS will auto-focus the message field if the user starts typing but no input field
* is focused.
*/
captureKeyboardEvents?: boolean;
/**
* Sets metadata for the current session.
*
* @remarks
* - `visible` manually sets the information about the visibility of TalkJS.
* This is useful when TalkJS is hidden with CSS. TalkJS will assume that UIs
* marked `visible: false` cannot be seen, and thus messages arriving on this UI will
* not be marked as read until you set `visible` to true again.
*
* - `custom` is an additional parameter to store the custom fields, that you
* may want to use in the REST API call.
*/
presence?: UserPresence;
/**
* Allows users to send and receive custom emojis.
*
* @remarks
* This adds a set of custom emoji images to the emoji picker, the emoji
* autocompleter, and emoji reactions.
*
* Every emoji name *must* start and end with a colon, for example `:lol:`.
* Emoji names can be up to 50 characters long, including the colons.
*
* Make sure you always specify a consistent, backward-compatible set of
* custom emojis. If an existing message contains a custom emoji that is not
* specified in `customEmojis` here, then the emoji cannot be displayed and
* the textual name will be displayed instead (including colons).
*
* If you want to allow an emoji to be displayed if it's used in existing
* data, but not let users select it in new messages/reactions, set the
* `hidden` option to `true` for that emoji.
*
* @example Create three custom emojis
* ```json
* {
* // Static image
* ":lol:": { url: "https://example.com/images/emoji-lol.svg" },
* // Animated
* ":roomba-cat:": { url: "https://example.com/images/roomba-cat.gif" },
* // Hidden
* ":alert:": { url: "https://example.com/images/alert.gif", hidden: true },
* }
* ```
*/
customEmojis?: {
[name: string]: CustomEmojiDefinition;
};
}
/** @public
* @hidden due to being empty
* @deprecated Use `popup.onClose(() => {...})` instead, without an event parameter
*/
declare interface CloseEvent_2 {
}
export { CloseEvent_2 as CloseEvent }
/**
* A node in a {@link TextBlock} that renders `text` in an inline code span (HTML `<code>`).
*
* @remarks
* Used when a user types ```text```.
*
* @public
*/
export declare interface CodeSpanNode {
type: "codeSpan";
text: string;
}
/**
* Allows you to filter conversations down to a specific subset.
*
* @remarks
* Use with {@link Inbox.setFeedFilter} or pass {@link InboxOptions.feedFilter} to
* {@link Session.createInbox}.
*
* The first element must be the string "any", and the second element a list of SimpleConversationPredicate objects.
*
* See {@link SimpleConversationPredicate} for all available options.
*
* @example Show conversations where you have read-only access, or whose custom `accountId` property is "my_account"
* ```json
* ["any", [{ access: ["==", "Read"] }, { custom: { accountId: ["==", "my_account"] } }]]
* ```
*
* @public
*/
export declare type CompoundConversationPredicate = [
"any",
SimpleConversationPredicate[]
];
/**
* Lets you show only specific messages in the chat panel of a Chatbox, Inbox or Popup.
*
* @remarks
* Used in methods like {@link Chatbox.setMessageFilter}.
*
* The first element must be the string "any", and the second element a list of SimpleMessagePredicate objects.
*
* See {@link SimpleMessagePredicate} for all available options.
*
* @example Only show system messages and messages from users with the "admin" role
* ```json
* ["any", [{ type: ["==", "SystemMessage"] }, { sender: {"role": ["==", "admin"] } }]]
* ```
*
* @public
*/
export declare type CompoundMessagePredicate = ["any", SimpleMessagePredicate[]];
/**
* The content of a message is structured as a list of content blocks.
*
* @remarks
* Currently, each message can only have one content block, but this will change in the future.
* This will not be considered a breaking change, so your code should assume there can be multiple content blocks.
*
* These blocks are rendered in order, top-to-bottom.
*
* Currently the available Content Block types are:
*
* - `type: "text"` ({@link TextBlock})
*
* - `type: "file"` ({@link FileBlock})
*
* - `type: "location"` ({@link LocationBlock})
*
* @public
*/
export declare type ContentBlock = TextBlock | FileBlock | LocationBlock;
/**
* Encapsulates an active conversation between two parties.
*
* @remarks
* Use this object to send system messages to the conversation or to programmatically select a
* conversation by passing it to {@link Inbox.select}.
*
* Conversation objects are created with the deprecated {@link Session.getOrStartConversation}
* method.
*
*
* @public
* @deprecated Use {@link ConversationRef} via {@link Session.conversation|Session.conversation()} instead
*/
export declare interface Conversation {
/**
* The ID of the conversation
*/
readonly id: string;
/**
* @hidden
* An array of {@link Participant | Participants} in the conversation.
*/
participants: Array<Participant>;
/**
* An optional conversation subject which is displayed in the chat header
* @remarks
* Set to `null` to delete the existing value (if any). When omitted or `undefined`, the existing value remains unchanged.
*/
subject?: string | null;
/**
* Optional custom conversation meta data
* @remarks
* Set any property to `null` to delete the existing value (if any). When omitted or `undefined`, the existing value remains unchanged.
*/
custom?: {
[name: string]: string | null;
} | null;
welcomeMessages?: Array<string> | null;
/**
* An optional URL to a photo which will be shown as the photo for the conversation.
* @remarks
* Set to `null` to delete the existing value (if any). When omitted or `undefined`, the existing value remains unchanged.
*/
photoUrl?: string | null;
}
/**
* @public
* A string that must be `"ReadWrite"`, `"Read"` or `"None"`.
*/
export declare type ConversationAccessLevel = "ReadWrite" | "Read" | "None";
/**
* @public
* Emitted from {@link Chatbox.onCustomConversationAction} when a user clicks on a
* custom action in a conversation within the TalkJS UI
*/
export declare interface ConversationActionEvent {
action: string;
params: ActionEventParams;
/**
* The value will be `null` if the conversation action is triggered
* from inside the `ConversationListHeader` component.
*/
conversation: ConversationData | null;
}
/**
* The state of a conversation subscription when it is actively listening for changes
*
* @public
*/
export declare interface ConversationActiveState {
type: "active";
/**
* The most recently received snapshot for the conversation, or `null` if you are not a participant in the conversation (including when the conversation does not exist).
*/
latestSnapshot: ConversationSnapshot | null;
}
/**
* Conversation attributes that can be set using {@link ConversationBuilder.setAttributes}
* @public
*/
export declare interface ConversationAttributes {
/**
* A human-readable subject of the conversation. Supports formatted links in a Markdown-style syntax, e.g.
* `Beautiful <https://example.com/booking/18644|home by the sea>!`.
* URLs and email addresses are made clickable, and emojis made to work cross-platform.
* @remarks
* Set to `null` to delete the existing value (if any). When omitted or `undefined`, the existing value remains unchanged.
*/
subject?: string | null;
/**
* The URL of a photo to be used for this conversation in the TalkJS UI in case there are more than 2 participants
* (TalkJS shows the photo of the other participant in a 1-on-1 conversation)
* @remarks
* Set to `null` to delete the existing value (if any). When omitted or `undefined`, the existing value remains unchanged.
*/
photoUrl?: string | null;
/**
* Custom metadata that is stored with the conversation
* @remarks
* Set any property to `null` to delete the existing value (if any). When omitted or `undefined`, the existing value remains unchanged.
*/
custom?: {
[key: string]: string | null;
} | null;
/**
* Messages which are sent at the beginning of a chat.
* In this case the messages will appear as system messages.
* @remarks
* Set to `null` to delete the existing value (if any). When omitted or `undefined`, the existing value remains unchanged.
*/
welcomeMessages?: Array<string> | null;
}
/**
* A Conversation Builder represents a conversation that is about to be created, fetched, or updated.
* You can use this object to set up or modify a conversation before showing it.
*
* @remarks
* To create a ConversationBuilder, call {@link Session.getOrCreateConversation}.
*
* Note: any changes you make here will not be sent to TalkJS immediately.
* Instead, instantiate a TalkJS UI using methods such as {@link Session.createInbox}.
*
* @classic New TalkJS integrations should use {@link ConversationRef} via {@link Session.conversation | Session.conversation()} instead.
* `ConversationRef` is part of the simpler and more powerful {@link https://talkjs.com/docs/Reference/JavaScript_Data_API/ | Data API}.
*
* @public
*/
export declare interface ConversationBuilder {
/**
* An optional conversation subject which will be displayed in the chat header.
* @remarks
* Set to `null` to delete the existing value (if any). When omitted or `undefined`, the existing value remains unchanged.
*/
subject?: string | null;
/**
* Allows custom conversation metadata to be stored in the form `{ [name: string]: string }`
* @remarks
* Set any property to `null` to delete the existing value (if any). When omitted or `undefined`, the existing value remains unchanged.
*/
custom?: {
[name: string]: string | null;
} | null;
/**
* An optional URL to a photo which will be shown as the photo for the conversation.
* @remarks
* Set to `null` to delete the existing value (if any). When omitted or `undefined`, the existing value remains unchanged.
*/
photoUrl?: string | null;
/**
* Messages which are sent at the beginning of a chat.
* In this case the messages will appear as system messages.
* @remarks
* Set to `null` to delete the existing value (if any). When omitted or `undefined`, the existing value remains unchanged.
*/
welcomeMessages?: Array<string> | null;
/**
* Sets a participant of the conversation.
*
* @remarks
* This method is idempotent and can be called multiple times.
*
* @param user - A `User` object that identifies the person who is a participant of the
* conversation. The user is uniquely identified by their id; all other fields (name, photo etc)
* are overwritten in the TalkJS database each time they change.
* @param settings - An optional setting of participation, can be an initial `access` right or
* if user should be notified.
*
* @classic The {@link https://talkjs.com/docs/Reference/JavaScript_Data_API/ | Data API} equivalent of `setParticipant` is {@link ParticipantRef.set}:
*
* ```ts
* session.conversation(convId).participant(userId).set({ notify: false });
* ```
*/
setParticipant(user: User, settings?: Partial<ParticipationSettings>): void;
/**
* Used to set certain attributes for a specific conversation
*
* @example Setting the conversation subject
* ```ts
* conversation.setAttributes({subject: "Booking question"});
* ```
*
* @example Setting the `custom.sold` and `custom.itemId` properties
* ```ts
* conversation.setAttributes({custom:
* {
* sold: "true",
* itemId: "720"
* }
* });
* ```
*
* If the conversation has any pre-existing custom properties, they will not be removed unless you set them to null.
*
* @classic The {@link https://talkjs.com/docs/Reference/JavaScript_Data_API/ | Data API} equivalent of `setAttributes` is {@link ConversationRef.set}:
*
* ```ts
* session.conversation(convId).set({ subject: "Booking question" });
* ```
*/
setAttributes(attributes: ConversationAttributes): void;
/**
* Sends a text message in a given conversation.
* @param text - The message body that is to be sent.
*
* @classic The {@link https://talkjs.com/docs/Reference/JavaScript_Data_API/ | Data API} equivalent of `sendMessage` is {@link ConversationRef.send}:
*
* ```ts
* session.conversation(convId).send("Hello");
* ```
*
* It can also send formatted messages, file attachments, and map locations.
*/
sendMessage(text: string, options?: SendMessageOptions): Promise<void>;
/**
* Removes the current user from this conversation.
*
* @returns A promise that resolves with true upon success (indicating that
* the user has been removed from this conversation), or false when the user
* did not have the appropriate permissions, as defined on the "Chat UI" page in the
* TalkJS dashboard). The promise may reject in case of an unexpected error.
*
* @classic The {@link https://talkjs.com/docs/Reference/JavaScript_Data_API/ | Data API} equivalent of `leave` is {@link ParticipantRef.delete}:
*
* ```ts
* session.conversation(convId).participant(session.currentUser).delete();
* ```
*/
leave(): Promise<boolean>;
}
/** @public */
export declare interface ConversationData {
/**
* The ID of the conversation
*/
id: string;
/**
* Contains custom metadata for the conversation if it was set using {@link ConversationBuilder.custom}.
* @remarks
* Set any property to `null` to delete the existing value (if any). When omitted or `undefined`, the existing value remains unchanged.
* When sending `custom: null` all properties and values will be removed.
*/
custom: CustomData;
/**
* Contains the conversation subject if it was set using {@link ConversationBuilder.subject}.
*/
subject: string | null;
/**
* Contains the URL of a photo that was set using {@link ConversationBuilder.subject}.
*/
photoUrl: string | null;
/**
* One or more welcome messages that will display to the user as a SystemMessage
*/
welcomeMessages: Array<string> | null;
/**
* A map of the access rights for the participants in this conversation.
*
* This property is not guaranteed to be complete.
* It always includes the current user, but does not always list other participants.
*
* Specifically, `ConversationData` returned from the following functions will only include the current user: `Session.onMessage`, `Session.onDesktopNotificationClicked`, `Session.unreads.onChange`.
* In all other cases, this field contains every participant in the conversation.
*
* Note on guest access:
* This field indicates a user's access as a participant.
* Guests always have "ReadWrite" access and are not included in this map
*/
participants: Record<string, {
access: "Read" | "ReadWrite";
}>;
}
/**
* The state of a conversation list subscription when it is actively listening for changes
*
* @public
*/
export declare interface ConversationListActiveState {
type: "active";
/**
* The most recently received snapshot for the conversations
*/
latestSnapshot: ConversationSnapshot[];
/**
* True if `latestSnapshot` contains all conversations you are in.
* Use {@link ConversationListSubscription.loadMore} to load more.
*/
loadedAll: boolean;
}
/**
* A subscription to your most recently active conversations.
*
* @remarks
* Get a ConversationListSubscription by calling {@link Session.subscribeConversations}.
*
* The subscription is 'windowed'. Initially, this window contains the 20 most recent conversations.
* Conversations are ordered by last activity. The last activity of a conversation is either `joinedAt` or `lastMessage.createdAt`, whichever is higher.
*
* The window will automatically expand to include any conversations you join, and any old conversations that receive new messages after subscribing.
*
* You can expand this window by calling {@link ConversationListSubscription.loadMore}, which extends the window further into the past.
*
* @public
*/
export declare interface ConversationListSubscription {
/**
* The current state of the subscription
*
* @remarks
* An object with the following fields:
*
* `type` is one of "pending", "active", "unsubscribed", or "error".
*
* When `type` is "active", includes `latestSnapshot` and `loadedAll`.
*
* - `latestSnapshot: ConversationSnapshot[]` the current state of the conversations in the window
*
* - `loadedAll: boolean` true when `latestSnapshot` contains all the conversations you are in
*
* When `type` is "error", includes the `error` field. It is a JS `Error` object explaining what caused the subscription to be terminated.
*/
state: PendingState | ConversationListActiveState | UnsubscribedState | ErrorState;
/**
* Resolves when the subscription starts receiving updates from the server.
*
* @remarks
* Wait for this promise if you want to perform some action as soon as the subscription is active.
*
* The promise rejects if the subscription is terminated before it connects.
*/
connected: Promise<ConversationListActiveState>;
/**
* Resolves when the subscription permanently stops receiving updates from the server.
*
* @remarks
* This is either because you unsubscribed or because the subscription encountered an unrecoverable error.
*/
terminated: Promise<UnsubscribedState | ErrorState>;
/**
* Expand the window to include older conversations
*
* @remarks
* Calling `loadMore` multiple times in parallel will still only load one page of conversations.
*
* @param count - The number of additional conversations to load. Must be between 1 and 30. Default 20.
* @returns A promise that resolves once the additional conversations have loaded
*/
loadMore(count?: number): Promise<void>;
/**
* Unsubscribe from this resource and stop receiving updates.
*
* @remarks
* If the subscription is already in the "unsubscribed" or "error" state, this is a no-op.
*/
unsubscribe(): void;
}
/**
* Allows you to filter conversations down to a specific subset.
*
* @remarks
* Use with {@link Inbox.setFeedFilter} or pass {@link InboxOptions.feedFilter} to
* {@link Session.createInbox}.
*
* The ConversationPredicate can be either of the following:
*
* - a single SimpleConversationPredicate object that filters based on all the fields of the predicate
*
* - an array that gives you all the conversations that satisfy at least one of the SimpleConversationPredicates
*
* See {@link SimpleConversationPredicate} and {@link CompoundConversationPredicate} for all available options.
*
* @public
*/
export declare type ConversationPredicate = SimpleConversationPredicate | CompoundConversationPredicate;
/**
* References the conversation with a given conversation ID, from the perspective of the current user.
*
* @remarks
* Used in all Data API operations affecting that conversation, such as fetching or updating conversation attributes.
* Created via {@link Session.conversation|Session.conversation()}.
*
* @public
*/
export declare interface ConversationRef {
/**
* The ID of the referenced conversation.
*
* @remarks
* Immutable: if you want to reference a different conversation, get a new ConversationRef instead.
*/
readonly id: string;
/**
* Get a reference to a participant in this conversation
*
* @remarks
* Note that `Participant` is not the same as `User`.
* A `Participant` represents a user's settings related to a specific conversation.
*
* Calling {@link ConversationRef.createIfNotExists|ConversationRef.createIfNotExists} or {@link ConversationRef.set|ConversationRef.set} will automatically add the current user as a participant.
*
* @example To add "Alice" to the conversation "Cats"
* ```ts
* session.conversation("Cats").participant("Alice").createIfNotExists();
* ```
*
* The user "Alice" must exist before you do this.
*
* @example To remove "Alice" from the conversation "Cats"
* ```ts
* session.conversation("Cats").participant("Alice").delete();
* ```
*
* The user "Alice" will still exist after you do this. This deletes the participant, not the user.
*
* @param user - Specifies which participant in the conversation you want to reference. Either the user's ID, or a reference to that user.
* @returns A {@linkcode ParticipantRef} for that user's participation in this conversation
* @throws If the user is not a UserRef or a non-empty string
* @public
*/
participant(user: string | UserRef): ParticipantRef;
/**
* Get a reference to a message in this conversation
*
* @remarks
* Use this if you need to fetch, delete, or edit a specific message in this conversation, and you know its message ID.
* To fetch the most recent messages in this conversation, use {@link ConversationRef.subscribeMessages} instead.
*
* @param id - The ID of the message that you want to reference
* @returns A {@linkcode MessageRef} for the message with that ID in this conversation
* @throws If the id is not a string or is an empty string
* @public
*/
message(id: string): MessageRef;
/**
* Fetches a snapshot of the conversation.
*
* @remarks
* This contains all of the information related to the conversation and the current user's participation in the conversation.
*
* @returns A snapshot of the current user's view of the conversation, or null if the current user is not a participant (including if the conversation doesn't exist).
*/
get(): Promise<ConversationSnapshot | null>;
/**
* Sets properties of this conversation and your participation in it.
*
* @remarks
* The conversation is created if a conversation with this ID doesn't already exist.
* You are added as a participant if you are not already a participant in the conversation.
*
* @returns A promise that resolves when the operation completes.
* When client-side conversation syncing is disabled, you must already be a participant and you cannot set anything except the `notify` property.
* Everything else requires client-side conversation syncing to be enabled, and will cause the promise to reject.
*/
set(params: SetConversationParams): Promise<void>;
/**
* Creates this conversation if it does not already exist.
* Adds you as a participant in this conversation, if you are not already a participant.
*
* @remarks
* If the conversation already exists or you are already a participant, this operation is still considered successful and the promise will still resolve.
*
* @returns A promise that resolves when the operation completes. The promise rejects if you are not already a participant and client-side conversation syncing is disabled.
*/
createIfNotExists(params?: CreateConversationParams): Promise<void>;
/**
* Marks the conversation as read.
*
* @returns A promise that resolves when the operation completes. The promise rejects if you are not a participant in the conversation.
*/
markAsRead(): Promise<void>;
/**
* Marks the conversation as unread.
*
* @returns A promise that resolves when the operation completes. The promise rejects if you are not a participant in the conversation.
*/
markAsUnread(): Promise<void>;
/**
* Sends a message in the conversation
*
* @example Send a simple message with markup (bold in this example)
* ```ts
* conversationRef.send("*Hello*");
* ```
*
* @example Reply to a message and set custom message data
* ```ts
* conversationRef.send({
* text: "Agreed",
* referencedMessageId: "...",
* custom: { priority: "HIGH" }
* });
* ```
*
* @example Send pre-formatted text with {@link TextBlock}
* ```ts
* conversationRef.send({
* content: [{
* type: "text",
* children: [{
* type: "bold",
* children: ["Hello"]
* }]
* }]
* });
* ```
*
* @example Send a file with {@link SendFileBlock}
* ```ts
* // `file` is a File object from `<input type="file">`
* const fileToken = await session.uploadImage(
* file, { filename: file.name, width: 640, height: 480 }
* );
*
* conversationRef.send({
* content: [{ type: "file", fileToken }]
* });
* ```
*
* @example Send a location with {@link LocationBlock}
* ```ts
* // You can get the user's location with the browser's geolocation API
* const [latitude, longitude] = [42.43, -83.99];
* conversationRef.send({
* content: [{ type: "location", latitude, longitude }]
* });
* ```
*
* @returns A promise that resolves with a reference to the newly created message. The promise will reject if you do not have permission to send the message.
*/
send(params: string | SendTextMessageParams | SendMessageParams): Promise<MessageRef>;
/**
* Subscribes to the messages in the conversation.
*
* @remarks
* Initially, you will be subscribed to the 30 most recent messages and any new messages.
* Call `loadMore` to load additional older messages.
*
* While the subscription is active, `onSnapshot` will be called whenever the message snapshots change.
* This includes when a message is sent, edited, deleted, and when you load more messages.
* It also includes when nested data changes, such as when `snapshot[0].referencedMessage.sender.name` changes.
* `loadedAll` is true when `snapshot` contains all the messages in the conversation, and false if you could load more.
*
* The snapshot is null if you are not a participant in the conversation (including when the conversation doesn't exist)
*/
subscribeMessages(onSnapshot?: (snapshot: MessageSnapshot[] | null, loadedAll: boolean) => void): MessageSubscription;
/**
* Subscribes to the participants in the conversation.
*
* @remarks
* Initially, you will be subscribed to the 10 participants who joined most recently, and any new participants.
* Call `loadMore` to load additional older participants.
*
* While the subscription is active, `onSnapshot` will be called whenever the participant snapshots change.
* This includes when someone joins or leaves, when their participant attributes are edited, and when you load more participants.
* It also includes when nested data changes, such as when `snapshot[0].user.name` changes.
* `loadedAll` is true when `snapshot` contains all the participants in the conversation, and false if you could load more.
*
* The snapshot is null if you are not a participant in the conversation (including when the conversation doesn't exist)
*/
subscribeParticipants(onSnapshot?: (snapshot: ParticipantSnapshot[] | null, loadedAll: boolean) => void): ParticipantSubscription;
/**
* Subscribes to the conversation.
*
* @remarks
* While the subscription is active, `onSnapshot` will be called when you join or leave the conversation, or when the snapshot changes.
* This includes changes to nested data. As an extreme example, `onSnapshot` would be called when `snapshot.lastMessage.referencedMessage.sender.name` changes.
*
* The snapshot is null if you are not a participant in the conversation (including when the conversation doesn't exist)
*/
subscribe(onSnapshot?: (snapshot: ConversationSnapshot | null) => void): ConversationSubscription;
/**
* Subscribes to the typing status of the conversation.
*
* @remarks
* While the subscription is active, `onSnapshot` will be called when you join or leave the conversation, or when the snapshot changes.
* This includes changes to the nested `UserSnapshot`s. If one of the people who is typing, changes their name, `onSnapshot` will be called.
* You will not be notified when there are already "many" people typing, and another person starts typing, because the snapshot does not change.
*
* The snapshot is null if you are not a participant in the conversation (including when the conversation doesn't exist)
*/
subscribeTyping(onSnapshot?: (snapshot: TypingSnapshot | null) => void): TypingSubscription;
/**
* Marks the current user as typing in this conversation for 10 seconds.
*
* @remarks
* This means that other users will see a typing indicator in the UI, from the current user.
*
* The user will automatically stop typing after 10 seconds. You cannot manually mark a user as "not typing".
* Users are also considered "not typing" when they send a message, even if that message was sent from a different tab or using the REST API.
*
* To keep the typing indicator visible for longer, call this function again to reset the 10s timer.
*
* @example Example implementation
* ```ts
* let lastMarkedAsTyping = 0;
*
* inputElement.addEventListener("change", event => {
* const text = event.target.value;
*
* // Deleting your draft never counts as typing
* if (text.length === 0) {
* return;
* }
*
* const now = Date.now();
*
* // Don't mark as typing more than once every 5s
* if (now - lastMarkedAsTyping > 5000) {
* lastMarkedAsTyping = now;
* convRef.markAsTyping();
* }
* });
*
* // When you send a message, you are no longer considered typing
* // So we need to send markAsTyping as soon as you type something
* function onSendMessage() {
* lastMarkedAsTyping = 0;
* }
* ```
*/
markAsTyping(): Promise<void>;
}
/** @public
*
* This represents the interface of the event triggered from {@link Inbox.onConversationSelected}.
*/
export declare interface ConversationSelectedEvent {
/**
* The current TalkJS User
*/
me: UserSnapshot;
/**
* @deprecated When you are the only participant in the conversation, this property includes the current user. Use `participants` and filter out the current user instead.
*
* The other participants in the conversation that are not the current user
*/
others?: Array<UserSnapshot>;
/**
* The participants in the conversation, including the current user
*/
participants?: Array<UserSnapshot>;
/**
* The current conversation object
*/
conversation: ConversationData | null;
}
/**
* A snapshot of a conversation's attributes at a given moment in time.
*
* @remarks
* Also includes information about the current user's view of that conversation, such as whether or not notifications are enabled.
*
* Snapshots are immutable and we try to reuse them when possible. You should only re-render your UI when `oldSnapshot !== newSnapshot`.
*
* @public
*/
export declare interface ConversationSnapshot {
/**
* The ID of the conversation
*/
id: string;
/**
* Contains the conversation subject, or `null` if the conversation does not have a subject specified.
*/
subject: string | null;
/**
* Contains the URL of a photo to represent the topic of the conversation or `null` if the conversation does not have a photo specified.
*/
photoUrl: string | null;
/**
* One or more welcome messages that will display to the user as a SystemMessage
*/
welcomeMessages: string[];
/**
* Custom metadata you have set on the conversation
*/
custom: Record<string, string>;
/**
* The date that the conversation was created, as a unix timestamp in milliseconds.
*/
createdAt: number;
/**
* The date that the current user joined the conversation, as a unix timestamp in milliseconds.
*/
joinedAt: number;
/**
* The last message sent in this conversation, or null if no messages have been sent.
*/
lastMessage: MessageSnapshot | null;
/**
* The number of messages in this conversation that the current user hasn't read.
*/
unreadMessageCount: number;
/**
* The most recent date that the current user read the conversation.
*
* @remarks
* This value is updated whenever you read a message in a chat UI, open an email notification, or mark the conversation as read using an API like {@link ConversationRef.markAsRead}.
*
* Any messages sent after this timestamp are unread messages.
*/
readUntil: number;
/**
* Everyone in the conversation has read any messages sent on or before this date.
*
* @remarks
* This is the minimum of all the participants' `readUntil` values.
* Any messages sent on or before this timestamp should show a "read" indicator in the UI.
*
* This value will rarely change in very large conversations.
* If just one person stops checking their messages, `everyoneReadUntil` will never update.
*/
everyoneReadUntil: number;
/**
* Whether the conversation should be considered unread.
*
* @remarks
* This can be true even when `unreadMessageCount` is zero, if the user has manually marked the conversation as unread.
*/
isUnread: boolean;
/**
* The current user's permission level in this conversation.
*/
access: "Read" | "ReadWrite";
/**
* The current user's notification settings for this conversation.
*
* @remarks
* `false` means no notifications, `true` means notifications for all messages, and `"MentionsOnly"` means that the user will only be notified when they are mentioned