UNPKG

@talkjs/core

Version:

Lets you connect to your TalkJS chat as a user and read, subscribe to, and update your chat data.

1,370 lines (1,332 loc) 95.4 kB
/** * 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[]; } /** * 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[]; } /** * 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; } 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; } /** * 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 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; } /** * 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; /** * 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; } /** * 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; } /** * 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 * @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 user that you want to reference * @returns A {@linkcode UserRef} for the user with that ID * @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. * * Whenever `Subscription.state.type` is "active" and a message is sent, edited, deleted, or you load more messages, `onSnapshot` will fire and `Subscription.state.latestSnapshot` will be updated. * `loadedAll` is true when the snapshot contains all the messages in the conversation. * * 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. * * Whenever `Subscription.state.type` is "active" and a participant is created, edited, deleted, or you load more participants, `onSnapshot` will fire and `Subscription.state.latestSnapshot` will be updated. * `loadedAll` is true when the snapshot contains all the participants in the conversation. * * 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 * Whenever `Subscription.state.type` is "active" and something about the conversation changes, `onSnapshot` will fire and `Subscription.state.latestSnapshot` will be updated. * 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 * Whenever `Subscription.state.type` is "active" and the typing status changes, `onSnapshot` will fire and `Subscription.state.latestSnapshot` will be updated. * This includes changes to nested data, such as when a user who is typing changes their name. * * The snapshot is null if you are not a participant in the conversation (including when the conversation doesn't exist) * * Note that if there are "many" people typing and another person starts to type, `onSnapshot` will not be called. * This is because your existing {@link ManyTypingSnapshot} is still valid and did not change when the new person started to type. */ 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>; } /** * 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 with an `@`. */ notify: boolean | "MentionsOnly"; } /** * A subscription to a specific conversation. * * @remarks * Get a ConversationSubscription by calling {@link ConversationRef.subscribe} * * @public */ export declare interface ConversationSubscription { /** * 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: ConversationSnapshot | null`, the current state of the conversation. * `latestSnapshot` is `null` when you are not a participant or the conversation does not exist. * * When `type` is "error", includes the `error` field. It is a JS `Error` object explaining what caused the subscription to be terminated. */ state: PendingState | ConversationActiveState | UnsubscribedState | ErrorState; /** * Resolves when the subscription starts receiving updates from the server. */ connected: Promise<ConversationActiveState>; /** * 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>; /** * 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; } /** * Parameters you can pass to {@link ConversationRef.createIfNotExists}. * * Properties that are `undefined` will be set to the default. * * @public */ export declare interface CreateConversationParams { /** * The conversation subject to display in the chat header. * Default = no subject, list participant names instead. */ subject?: string; /** * The URL for the conversation photo to display in the chat header. * Default = no photo, show a placeholder image. */ photoUrl?: string; /** * System messages which are sent at the beginning of a conversation. * Default = no messages. */ welcomeMessages?: string[]; /** * Custom metadata you have set on the conversation. * This value acts as a patch. Remove specific properties by setting them to `null`. * Default = no custom metadata */ custom?: Record<string, string>; /** * Your access to the conversation. * Default = "ReadWrite" access. */ access?: "Read" | "ReadWrite"; /** * Your notification settings. * Default = `true` */ notify?: boolean | "MentionsOnly"; } /** * Parameters you can pass to {@link ParticipantRef.createIfNotExists}. * * @remarks * Properties that are `undefined` will be set to the default. * * @public */ export declare interface CreateParticipantParams { /** * The level of access the participant should have in the conversation. * Default = "ReadWrite" access. */ access?: "ReadWrite" | "Read"; /** * When the participant should be notified about new messages in this conversation. * Default = `true` * * @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 with an `@`. */ notify?: boolean | "MentionsOnly"; } /** * Parameters you can pass to {@link UserRef.createIfNotExists}. * * @remarks * Properties that are `undefined` will be set to the default. * * @public */ export declare interface CreateUserParams { /** * The user's name which is displayed on the TalkJS UI */ name: string; /** * Custom metadata you have set on the user. * Default = no custom metadata */ custom?: Record<string, string>; /** * An {@link https://www.w3.org/International/articles/language-tags/ | IETF language tag}. * See the {@link https://talkjs.com/docs/Features/Language_Support/Localization.html | localization documentation} * Default = the locale selected on the dashboard */ locale?: string; /** * An optional URL to a photo that is displayed as the user's avatar. * Default = no photo */ photoUrl?: string; /** * TalkJS supports multiple sets of settings, called "roles". These allow you to change the behavior of TalkJS for different users. * You have full control over which user gets which configuration. * Default = the `default` role */ role?: string; /** * The default message a person sees when starting a chat with this user. * Default = no welcome message */ welcomeMessage?: string; /** * A single email address or an array of email addresses associated with the user. * Default = no email addresses */ email?: string | string[]; /** * A single phone number or an array of phone numbers associated with the user. * Default = no phone numbers */ phone?: string | string[]; /** * An object of push registration tokens to use when notifying this user. * * Keys in the object have the format `'provider:token_id'`, * where `provider` is either `"fcm"` for Android (Firebase Cloud Messaging), * or `"apns"` for iOS (Apple Push Notification Service). * * Default = no push registration tokens */ pushTokens?: Record<string, true>; } /** * A node in a {@link TextBlock} that is used for {@link https://talkjs.com/docs/Features/Message_Features/Emoji_Reactions/#custom-emojis | custom emoji}. * * @public */ export declare interface CustomEmojiNode { type: "customEmoji"; /** * The name of the custom emoji to show. */ text: string; } /** * Parameters you can pass to {@link MessageRef.edit}. * * @remarks * Properties that are `undefined` will not be changed. * To clear / reset a property to the default, pass `null`. * * This is the more advanced method for editing a message. It gives you full control over the message content. * You can decide exactly how a text message should be formatted, edit an attachment, or even turn a text message into a location. * * @public */ export declare interface EditMessageParams { /** * Custom metadata you have set on the message. * This value acts as a patch. Remove specific properties by setting them to `null`. * Default = no custom metadata */ custom?: Record<string, string | null> | null; /** * The new content for the message. * * @remarks * Any value provided here will overwrite the existing message content. * * By default users do not have permission to send {@link LinkNode}, {@link ActionLinkNode}, or {@link ActionButtonNode}, as they can be used to trick the recipient. */ content?: [SendContentBlock]; } /** * Parameters you can pass to {@link MessageRef.edit}. * * @remarks * Properties that are `undefined` will not be changed. * To clear / reset a property to the default, pass `null`. * * This is a simpler version of {@link EditMessageParams} that only supports setting the message content to text. * * @public */ export declare interface EditTextMessageParams { /** * Custom metadata you have set on the message. * This value acts as a patch. Remove specific properties by setting them to `null`. * Default = no custom metadata */ custom?: Record<string, string | null> | null; /** * The new text to set in the message body. * * @remarks * This is parsed the same way as the text entered in the message field. For example, `*hi*` will appear as `hi` in bold. * * See the {@link https://talkjs.com/docs/Features/Message_Features/Formatting/ | message formatting documentation} for more details. */ text?: string; } /** * The state of a subscription after it encounters an unrecoverable error * * @public */ export declare interface ErrorState { type: "error"; /** * The error that caused the subscription to be terminated */ error: Error; } /** * The {@link TypingSnapshot} variant used when only a few people are typing. */ export declare interface FewTypingSnapshot { /** * Check this to differentiate between FewTypingSnapshot (`false`) and ManyTypingSnapshot (`true`). * * @remarks * When `false`, you can see the list of users who are typing in the `users` property. */ many: false; /** * The users who are currently typing in this conversation. * * @remarks * The list is in chronological order, starting with the users who have been typing the longest. * The current user is never contained in the list, only other users. */ users: UserSnapshot[]; } /** * A file attachment received in a message's content. * * @remarks * All `FileBlock` variants contain `url`, `size`, and `fileToken`. * Some file blocks have additional metadata, in which case they will have the `subtype` property set. * * Currently the available FileBlock subtypes are: * * - No `subtype` set ({@link GenericFileBlock}) * * - `subtype: "video"` ({@link VideoBlock}) * * - `subtype: "image"` ({@link ImageBlock}) * * - `subtype: "audio"` ({@link AudioBlock}) * * - `subtype: "voice"` ({@link VoiceBlock}) * * @public */ export declare type FileBlock = VideoBlock | ImageBlock | AudioBlock | VoiceBlock | GenericFileBlock; /** * A token representing a file uploaded to TalkJS. * * @remarks * You cannot create a FileToken yourself. Get a file token by uploading your file to TalkJS with {@link Session.uploadFile}, or one of the subtype-specific variants like {@link Session.uploadImage}. * Alternatively, take a file token from an existing {@link FileBlock} to re-send an attachment you received, without having to download and re-upload the file. * You can also upload files using the {@link https://talkjs.com/docs/Reference/REST_API/Messages/#1-upload-a-file| REST API}. * This system ensures that all files must be uploaded to TalkJS before being sent to users, limiting the risk of malware. * * Passed in {@link SendFileBlock} when you send a message containing a file attachment. * * We may change the FileToken format in the future. * Do not store old file tokens for future use, as these may stop working. * * @example Using a file input * ```ts * // From `<input type="file">` * const file: File = fileInputElement.files[0]; * const myFileToken = await session.uploadFile(file, { filename: file.name }); * * const block = { * type: 'file', * fileToken: myFileToken, * }; * session.conversation('example_conversation_id').send({ content: [block] }); * ``` * * @example Re-sending a file from a previous message * ```ts * session.conversation('example_conversation_id').send({ * content: previousMessageSnapshot.content * }); * ``` * * @public */ export declare type FileToken = string & { __tag: Record<"TalkJS Encoded File Token", true>; }; /** * The most basic FileBlock variant, used whenever there is no additional metadata for a file. * * @remarks * Do not try to check for `subtype === undefined` directly, as this will break when we add new FileBlock variants in the future. * * Instead, treat GenericFileBlock as the default. For example: * * ```ts * if (block.subtype === "video") { * handleVideoBlock(block); * } else if (block.subtype === "image") { * handleImageBlock(block); * } else if (block.subtype === "audio") { * handleAudioBlock(block); * } else if (block.subtype === "voice") { * handleVoiceBlock(block); * } else { * handleGenericFileBlock(block); * } * ``` * * @public */ export declare interface GenericFileBlock { type: "file"; /** * Never set for generic file blocks. */ subtype?: undefined; /** * 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 file, including file extension */ filename: string; } export declare interface GenericFileMetadata { /** * The name of the file including extension. */ filename: string; } /** * Returns a TalkSession for the specified App ID and User ID. * * @remarks * Backed by a registry, so calling this function twice with the same app and user returns the same session object both times. * A new session will be created if the old one encountered an error or got garbage collected. * * The `token` and `tokenFetcher` properties are ignored if there is already a session for that user in the registry. */ export declare function getTalkSession(options: TalkSessionOptions): TalkSession; /** * A FileBlock variant for an image attachment, with additional image-specific metadata. * * @remarks * You can identify this variant by checking for `subtype: "image"`. * * Includes metadata about the height and width of the image in pixels, where available. * * Images that you upload with the TalkJS UI will include the image dimensions as long as the sender's browser can preview the file. * Images that you upload with the REST API or {@link Session.uploadImage} will include the dimensions if you specified them when uploading. * Image attached in a reply to an email notification will not include the dimensions. * * @public */ export declare interface ImageBlock { type: "file"; subtype: "image"; /** * An encoded identifier for this file. Use in {@link SendFileBlock} to send this image 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 image file, including file extension. */ filename: string; /** * The width of the image in pixels, if known. */ width?: number; /** * The height of the image in pixels, if known. */ height?: number; } export declare interface ImageFileMetadata { /** * The name of the file including extension. */ filename: string; /** * The width of the image in pixels, if known. */ width?: number; /** * The height of the image in pixels, if known. */ height?: number; } /** * A node in a {@link TextBlock} that renders its children as a clickable link (HTML `<a>`). * * @remarks * By default, users do not have permission to send messages containing `LinkNode` as it can be used to maliciously hide the true destination of a link. * * @public */ export declare interface LinkNode { type: "link"; /** * The URL to open when the node is clicked. */ url: string; children: TextNode[]; } /** * A block showing a location in the world, typically because a user shared their location in the chat. * * @remarks * In the TalkJS UI, location blocks are rendered as a link to Google Maps, with the map pin showing at the specified coordinate. * A thumbnail shows the surrounding area on the map. * * @public */ export declare interface LocationBlock { type: "location"; /** * The north-south coordinate of the location. * * @remarks * Usually listed first in a pair of coordinates. * * Must be a number between -90 and 90 */ latitude: number; /** * The east-west coordinate of the location. * * @remarks * Usually listed second in a pair of coordinates. * * Must be a number between -180 and 180 */ longitude: number; } /** * The {@link TypingSnapshot} variant used when many people are typing. */ export declare interface ManyTypingSnapshot { /** * Check this to differentiate between FewTypingSnapshot (`false`) and ManyTypingSnapshot (`true`). * * @remarks * When `true`, you do not receive a list of users who are typing. * You should show a message like "several people are typing" instead. */ many: true; } /** * A node in a {@link TextBlock} that renders its children with a specific style. * * @public */ export declare interface MarkupNode { /** * The kind of formatting to apply when rendering the children * * - `type: "bold"` is used when users type `*text*` and is rendered with HTML `<strong>` * * - `type: "italic"` is used when users type `_text_` and is rendered with HTML `<em>` * * - `type: "strikethrough"` is used when users type `~text~` and is rendered with HTML `<s>` */ type: "bold" | "italic" | "strikethrough"; children: TextNode[]; } /** * A node in a {@link TextBlock} that is used when a user is {@link https://talkjs.com/docs/Features/Message_Features/Mentions/ | mentioned}. * * @remarks * Used when a user types `@name` and selects the user they want to mention. * * @public */ export declare interface MentionNode { type: "mention"; /** * The ID of the user who is mentioned. */ id: string; /** * The name of the user who is mentioned. */ text: string; } /** * The state of a messages subscription when it is actively listening for changes * * @public */ export declare interface MessageActiveState { type: "active"; /** * The most recently received snapshot for the user, or `null` if the user does not exist yet. */ latestSnapshot: MessageSnapshot[] | null; /** * True if `latestSnapshot` contains all messages in the conversation. * Use {@link MessageSubscription.loadMore} to load more. */ loadedAll: boolean; } /** * References the message with a given message ID. * * @remarks * Used in all Data API operations affecting that message, such as fetching or editing the message attributes, or deleting the message. * Created via {@link ConversationRef.message} and {@link ConversationRef.send}. * * @public */ export declare interface MessageRef { /** * The ID of the referenced message. * * @remarks * Immutable: if you want to reference a different message, get a new MessageRef instead. */ readonly id: string; /** * The ID of the conversation that the referenced message belongs to. * * @remarks * Immutable: if you want to reference a message from a different conversation, get a new MessageRef from that conversation. */ readonly conversationId: string; /** * Fetches a snapshot of the message. * * @remarks * Supports {@link https://talkjs.com/docs/Reference/JavaScript_Data_API/Performance/#cached-fetch | Cached Fetch} * * @returns A snapshot of the message's attributes, or null if the message doesn't exist, the conversation doesn't exist, or you're not a participant in the conversation. */ get(): Promise<MessageSnapshot | null>; /** * Edits this message. * * @returns A promise that resolves when the operation completes. The promise will reject if the request is invalid, the message doesn't exist, or you do not have permission to edit that message. */ edit(params: string | EditTextMessageParams | EditMessageParams): Promise<void>; /** * Deletes this message, or does nothing if they are already not a participant. * * @remarks * Deleting a nonexistent message is treated as success, and the promise will resolve. * * @returns A promise that resolves when the operation completes. This promise will reject if you are not a participant in the conversation or if your role does not give you permission to delete this message. */ delete(): Promise<void>; } /** * A snapshot of a message's attributes at a given moment in time. * * @remarks * Automatically expanded to include a snapshot of the user that sent the message, and a snapshot of the referenced message, if this message is a reply. * * 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 MessageSnapshot { /** * The unique ID that is used to identify the message in TalkJS */ id: string; /** * Whether this message was "from a user" or a general system message without a specific sender. * * The `sender` property is always present for "UserMessage" messages and never present for "SystemMessage" messages. */ type: "UserMessage" | "SystemMessage"; /** * A snapshot of the user who sent the message, or null if it is a system message. * The user's attributes may have been updated since they sent the message, in which case this snapshot contains the updated data. * It is not a historical snapshot. */ sender: UserSnapshot | null; /** * Custom metadata you have set on the message */ custom: Record<string, string>; /** * Time at which the message was sent, as a unix timestamp in milliseconds */ createdAt: number; /** * Time at which the message was last edited, as a unix timestamp in milliseconds. * `null` if the message has never been edited. */ editedAt: number | null; /** * A snapshot of the message that this message is a reply to, or null if this message is not a reply. * * @remarks * Only UserMessages can reference other messages. * The referenced message snapshot does not have a `referencedMessage` field. * Instead, it has `referencedMessageId`. * This prevents TalkJS fetching an unlimited number of messages in a long chain of replies. */ referencedMessage: ReferencedMessageSnapshot | null; /** * Where this message originated from: * * - "web" = Message sent via the UI or via {@link ConversationBuilder.sendMessage} * * - "rest" = Message sent via the REST API's "send message" endpoint or {@link ConversationRef.send} * * - "import" = Message sent via the REST API's "import messages" endpoint * * - "email" = Message sent by replying to an email notification */ origin: "web" | "rest" | "import" | "email"; /** * The contents of the message, as a plain text string without any formatting or attachments. * Useful for showing in a conversation list or in notifications. */ plaintext: string; /** * The main body of the message, as a list of blocks that are rendered top-to-bottom. */ content: ContentBlock[]; } /** * A subscription to the messages in a specific conversation. * * @remarks * Get a MessageSubscription by calling {@link ConversationRef.subscribeMessages} * * The subscription is 'windowed'. It includes all messages since a certain point in time. * By default, you subscribe to the 30 most recent messages, and any new messages that are sent after you subscribe. * * You can expand this window by calling {@link MessageSubscription.loadMore}, which extends the window further into the past. * * @public */ export declare interface MessageSubscription { /** * 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: MessageSnapshot[] | null` the current state of the messages in the window, or null if you're not a participant in the conversation * * - `loadedAll: boolean` true when `latestSnapshot` contains all the messages in the conversation * * When `type` is "error", includes the `error` field. It is a JS `Error` object explaining what caused the subscription to be terminated. */ state: Pendi