stream-chat 9.20.2 → 9.20.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/index.ts", "../../src/base64.ts", "../../src/campaign.ts", "../../src/client.ts", "../../src/utils.ts", "../../src/constants.ts", "../../src/channel_state.ts", "../../src/messageComposer/attachmentIdentity.ts", "../../src/messageComposer/fileUtils.ts", "../../src/messageComposer/middleware/attachmentManager/postUpload/attachmentEnrichment.ts", "../../src/utils/concurrency.ts", "../../src/middleware.ts", "../../src/messageComposer/middleware/attachmentManager/postUpload/uploadErrorHandler.ts", "../../src/messageComposer/middleware/attachmentManager/postUpload/AttachmentPostUploadMiddlewareExecutor.ts", "../../src/messageComposer/middleware/attachmentManager/preUpload/serverUploadConfigCheck.ts", "../../src/messageComposer/middleware/attachmentManager/preUpload/blockedUploadNotification.ts", "../../src/messageComposer/middleware/attachmentManager/preUpload/AttachmentPreUploadMiddlewareExecutor.ts", "../../src/store.ts", "../../src/utils/mergeWith/mergeWithCore.ts", "../../src/utils/mergeWith/mergeWith.ts", "../../src/utils/mergeWith/mergeWithDiff.ts", "../../src/messageComposer/attachmentManager.ts", "../../src/messageComposer/configuration/configuration.ts", "../../src/messageComposer/CustomDataManager.ts", "../../src/messageComposer/linkPreviewsManager.ts", "../../src/messageComposer/LocationComposer.ts", "../../src/messageComposer/middleware/pollComposer/state.ts", "../../src/messageComposer/middleware/pollComposer/composition.ts", "../../src/messageComposer/middleware/pollComposer/PollComposerMiddlewareExecutor.ts", "../../src/types.ts", "../../src/messageComposer/pollComposer.ts", "../../src/messageComposer/middleware/messageComposer/attachments.ts", "../../src/messageComposer/middleware/messageComposer/cleanData.ts", "../../src/messageComposer/middleware/messageComposer/customData.ts", "../../src/messageComposer/middleware/messageComposer/compositionValidation.ts", "../../src/messageComposer/middleware/messageComposer/linkPreviews.ts", "../../src/messageComposer/middleware/messageComposer/textComposer.ts", "../../src/messageComposer/middleware/messageComposer/messageComposerState.ts", "../../src/messageComposer/middleware/messageComposer/userDataInjection.ts", "../../src/messageComposer/middleware/messageComposer/pollOnly.ts", "../../src/messageComposer/middleware/messageComposer/sharedLocation.ts", "../../src/messageComposer/middleware/messageComposer/MessageComposerMiddlewareExecutor.ts", "../../src/messageComposer/middleware/messageComposer/commandInjection.ts", "../../src/messageComposer/middleware/textComposer/activeCommandGuard.ts", "../../src/search/BaseSearchSource.ts", "../../src/search/SearchController.ts", "../../src/pagination/BasePaginator.ts", "../../src/pagination/FilterBuilder.ts", "../../src/pagination/ReminderPaginator.ts", "../../src/search/UserSearchSource.ts", "../../src/search/ChannelSearchSource.ts", "../../src/search/MessageSearchSource.ts", "../../src/messageComposer/middleware/textComposer/textMiddlewareUtils.ts", "../../src/messageComposer/middleware/textComposer/commands.ts", "../../src/messageComposer/middleware/textComposer/commandStringExtraction.ts", "../../src/messageComposer/middleware/textComposer/mentions.ts", "../../src/messageComposer/middleware/textComposer/validation.ts", "../../src/messageComposer/middleware/textComposer/TextComposerMiddlewareExecutor.ts", "../../src/messageComposer/textComposer.ts", "../../src/utils/WithSubscriptions.ts", "../../src/thread.ts", "../../src/messageComposer/messageComposer.ts", "../../src/channel.ts", "../../src/client_state.ts", "../../src/connection.ts", "../../src/insights.ts", "../../src/signing.ts", "../../src/token_manager.ts", "../../src/connection_fallback.ts", "../../src/errors.ts", "../../src/segment.ts", "../../src/moderation.ts", "../../src/thread_manager.ts", "../../src/poll.ts", "../../src/poll_manager.ts", "../../src/channel_manager.ts", "../../src/notifications/configuration.ts", "../../src/notifications/NotificationManager.ts", "../../src/reminders/ReminderTimer.ts", "../../src/reminders/Reminder.ts", "../../src/reminders/ReminderManager.ts", "../../src/events.ts", "../../src/permissions.ts", "../../src/offline-support/types.ts", "../../src/offline-support/offline_sync_manager.ts", "../../src/offline-support/offline_support_api.ts", "../../src/LiveLocationManager.ts", "../../src/utils/FixedSizeQueueCache.ts"],
4
+ "sourcesContent": ["export * from './base64';\nexport * from './campaign';\nexport * from './client';\nexport * from './client_state';\nexport * from './channel';\nexport * from './channel_state';\nexport * from './connection';\nexport * from './events';\nexport * from './insights';\nexport * from './messageComposer';\nexport * from './middleware';\nexport * from './moderation';\nexport * from './notifications';\nexport * from './pagination';\nexport * from './permissions';\nexport * from './poll';\nexport * from './poll_manager';\nexport * from './reminders';\nexport * from './search';\nexport * from './segment';\nexport * from './signing';\nexport * from './store';\nexport { Thread } from './thread';\nexport type {\n ThreadState,\n ThreadReadState,\n ThreadRepliesPagination,\n ThreadUserReadState,\n} from './thread';\nexport * from './thread_manager';\nexport * from './token_manager';\nexport * from './types';\nexport * from './channel_manager';\nexport * from './offline-support';\nexport * from './LiveLocationManager';\n// Don't use * here, that can break module augmentation https://github.com/microsoft/TypeScript/issues/46617\nexport type {\n CustomAttachmentData,\n CustomChannelData,\n CustomCommandData,\n CustomEventData,\n CustomMemberData,\n CustomMessageComposerData,\n CustomMessageData,\n CustomPollOptionData,\n CustomPollData,\n CustomReactionData,\n CustomUserData,\n CustomThreadData,\n} from './custom_types';\nexport {\n isOwnUser,\n chatCodes,\n logChatPromiseExecution,\n localMessageToNewMessagePayload,\n formatMessage,\n promoteChannel,\n} from './utils';\nexport { FixedSizeQueueCache } from './utils/FixedSizeQueueCache';\n", "import { fromByteArray } from 'base64-js';\n\nfunction isString<T>(arrayOrString: string | T[]): arrayOrString is string {\n return typeof (arrayOrString as string) === 'string';\n}\n\ntype MapGenericCallback<T, U> = (value: T, index: number, array: T[]) => U;\ntype MapStringCallback<U> = (value: string, index: number, string: string) => U;\n\nfunction isMapStringCallback<T, U>(\n arrayOrString: string | T[],\n callback: MapGenericCallback<T, U> | MapStringCallback<U>,\n): callback is MapStringCallback<U> {\n return !!callback && isString(arrayOrString);\n}\n\n// source - https://github.com/beatgammit/base64-js/blob/master/test/convert.js#L72\nfunction map<T, U>(array: T[], callback: MapGenericCallback<T, U>): U[];\nfunction map<U>(string: string, callback: MapStringCallback<U>): U[];\nfunction map<T, U>(\n arrayOrString: string | T[],\n callback: MapGenericCallback<T, U> | MapStringCallback<U>,\n): U[] {\n const res = [];\n\n if (isString(arrayOrString) && isMapStringCallback(arrayOrString, callback)) {\n for (let k = 0, len = arrayOrString.length; k < len; k++) {\n if (arrayOrString.charAt(k)) {\n const kValue = arrayOrString.charAt(k);\n const mappedValue = callback(kValue, k, arrayOrString);\n res[k] = mappedValue;\n }\n }\n } else if (!isString(arrayOrString) && !isMapStringCallback(arrayOrString, callback)) {\n for (let k = 0, len = arrayOrString.length; k < len; k++) {\n if (k in arrayOrString) {\n const kValue = arrayOrString[k];\n const mappedValue = callback(kValue, k, arrayOrString);\n res[k] = mappedValue;\n }\n }\n }\n\n return res;\n}\n\nexport const encodeBase64 = (data: string): string =>\n fromByteArray(new Uint8Array(map(data, (char) => char.charCodeAt(0))));\n\n// base-64 decoder throws exception if encoded string is not padded by '=' to make string length\n// in multiples of 4. So gonna use our own method for this purpose to keep backwards compatibility\n// https://github.com/beatgammit/base64-js/blob/master/index.js#L26\nexport const decodeBase64 = (s: string): string => {\n const e = {} as { [key: string]: number },\n w = String.fromCharCode,\n L = s.length;\n let i,\n b = 0,\n c,\n x,\n l = 0,\n a,\n r = '';\n const A = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';\n for (i = 0; i < 64; i++) {\n e[A.charAt(i)] = i;\n }\n for (x = 0; x < L; x++) {\n c = e[s.charAt(x)];\n b = (b << 6) + c;\n l += 6;\n while (l >= 8) {\n // eslint-disable-next-line @typescript-eslint/no-unused-expressions\n ((a = (b >>> (l -= 8)) & 0xff) || x < L - 2) && (r += w(a));\n }\n }\n return r;\n};\n", "import type { StreamChat } from './client';\nimport type { CampaignData, GetCampaignOptions } from './types';\n\nexport class Campaign {\n id: string | null;\n data?: CampaignData;\n client: StreamChat;\n\n constructor(client: StreamChat, id: string | null, data?: CampaignData) {\n this.client = client;\n this.id = id;\n this.data = data;\n }\n\n async create() {\n const body = {\n id: this.id,\n message_template: this.data?.message_template,\n segment_ids: this.data?.segment_ids,\n sender_id: this.data?.sender_id,\n sender_mode: this.data?.sender_mode,\n sender_visibility: this.data?.sender_visibility,\n channel_template: this.data?.channel_template,\n create_channels: this.data?.create_channels,\n show_channels: this.data?.show_channels,\n description: this.data?.description,\n name: this.data?.name,\n skip_push: this.data?.skip_push,\n skip_webhook: this.data?.skip_webhook,\n user_ids: this.data?.user_ids,\n };\n\n const result = await this.client.createCampaign(body);\n\n this.id = result.campaign.id;\n this.data = result.campaign;\n return result;\n }\n\n verifyCampaignId() {\n if (!this.id) {\n throw new Error(\n 'Campaign id is missing. Either create the campaign using campaign.create() or set the id during instantiation - const campaign = client.campaign(id)',\n );\n }\n }\n\n async start(options?: { scheduledFor?: string; stopAt?: string }) {\n this.verifyCampaignId();\n\n return await this.client.startCampaign(this.id as string, options);\n }\n\n update(data: Partial<CampaignData>) {\n this.verifyCampaignId();\n\n return this.client.updateCampaign(this.id as string, data);\n }\n\n async delete() {\n this.verifyCampaignId();\n\n return await this.client.deleteCampaign(this.id as string);\n }\n\n stop() {\n this.verifyCampaignId();\n\n return this.client.stopCampaign(this.id as string);\n }\n\n get(options?: GetCampaignOptions) {\n this.verifyCampaignId();\n\n return this.client.getCampaign(this.id as string, options);\n }\n}\n", "/* eslint no-unused-vars: \"off\" */\n/* global process */\n\nimport type { AxiosError, AxiosInstance, AxiosRequestConfig, AxiosResponse } from 'axios';\nimport axios from 'axios';\nimport https from 'https';\nimport type WebSocket from 'isomorphic-ws';\n\nimport { Channel } from './channel';\nimport { ClientState } from './client_state';\nimport { StableWSConnection } from './connection';\nimport { CheckSignature, DevToken, JWTUserToken } from './signing';\nimport { TokenManager } from './token_manager';\nimport { WSConnectionFallback } from './connection_fallback';\nimport { Campaign } from './campaign';\nimport { Segment } from './segment';\nimport { isErrorResponse, isWSFailure } from './errors';\nimport {\n addFileToFormData,\n axiosParamsSerializer,\n chatCodes,\n generateChannelTempCid,\n isFunction,\n isOnline,\n isOwnUserBaseProperty,\n messageSetPagination,\n normalizeQuerySort,\n randomId,\n retryInterval,\n sleep,\n toUpdatedMessagePayload,\n} from './utils';\n\nimport type {\n ActiveLiveLocationsAPIResponse,\n APIErrorResponse,\n APIResponse,\n AppSettings,\n AppSettingsAPIResponse,\n BannedUsersFilters,\n BannedUsersPaginationOptions,\n BannedUsersResponse,\n BannedUsersSort,\n BanUserOptions,\n BaseDeviceFields,\n BlockList,\n BlockListResponse,\n BlockUserAPIResponse,\n CampaignData,\n CampaignFilters,\n CampaignQueryOptions,\n CampaignResponse,\n CampaignSort,\n CastVoteAPIResponse,\n ChannelAPIResponse,\n ChannelData,\n ChannelFilters,\n ChannelMute,\n ChannelOptions,\n ChannelResponse,\n ChannelSort,\n ChannelStateOptions,\n CheckPushResponse,\n CheckSNSResponse,\n CheckSQSResponse,\n Configs,\n ConnectAPIResponse,\n CreateChannelOptions,\n CreateChannelResponse,\n CreateCommandOptions,\n CreateCommandResponse,\n CreateImportOptions,\n CreateImportResponse,\n CreateImportURLResponse,\n CreatePollAPIResponse,\n CreatePollData,\n CreatePollOptionAPIResponse,\n CreateReminderOptions,\n CustomPermissionOptions,\n DeactivateUsersOptions,\n DeleteChannelsResponse,\n DeleteCommandResponse,\n DeleteUserOptions,\n Device,\n DeviceIdentifier,\n DraftFilters,\n DraftSort,\n EndpointName,\n Event,\n EventHandler,\n ExportChannelOptions,\n ExportChannelRequest,\n ExportChannelResponse,\n ExportChannelStatusResponse,\n ExportUsersRequest,\n ExportUsersResponse,\n FlagMessageResponse,\n FlagReportsFilters,\n FlagReportsPaginationOptions,\n FlagReportsResponse,\n FlagsFilters,\n FlagsPaginationOptions,\n FlagsResponse,\n FlagUserResponse,\n GetBlockedUsersAPIResponse,\n GetCampaignOptions,\n GetChannelTypeResponse,\n GetCommandResponse,\n GetHookEventsResponse,\n GetImportResponse,\n GetMessageAPIResponse,\n GetMessageOptions,\n GetPollAPIResponse,\n GetPollOptionAPIResponse,\n GetRateLimitsResponse,\n GetThreadAPIResponse,\n GetThreadOptions,\n GetUnreadCountAPIResponse,\n GetUnreadCountBatchAPIResponse,\n ListChannelResponse,\n ListCommandsResponse,\n ListImportsPaginationOptions,\n ListImportsResponse,\n LocalMessage,\n Logger,\n MarkChannelsReadOptions,\n MessageFilters,\n MessageFlagsFilters,\n MessageFlagsPaginationOptions,\n MessageFlagsResponse,\n MessageResponse,\n Mute,\n MuteUserOptions,\n MuteUserResponse,\n NewMemberPayload,\n OGAttachment,\n OwnUserResponse,\n Pager,\n PartialMessageUpdate,\n PartialPollUpdate,\n PartialThreadUpdate,\n PartialUserUpdate,\n PermissionAPIResponse,\n PermissionsAPIResponse,\n PollAnswersAPIResponse,\n PollData,\n PollOptionData,\n PollSort,\n PollVote,\n PollVoteData,\n PollVotesAPIResponse,\n Product,\n PushPreference,\n PushProvider,\n PushProviderConfig,\n PushProviderID,\n PushProviderListResponse,\n PushProviderUpsertResponse,\n QueryChannelsAPIResponse,\n QueryDraftsResponse,\n QueryMessageHistoryFilters,\n QueryMessageHistoryOptions,\n QueryMessageHistoryResponse,\n QueryMessageHistorySort,\n QueryPollsFilters,\n QueryPollsOptions,\n QueryPollsResponse,\n QueryReactionsAPIResponse,\n QueryReactionsOptions,\n QueryRemindersOptions,\n QueryRemindersResponse,\n QuerySegmentsOptions,\n QuerySegmentTargetsFilter,\n QueryThreadsAPIResponse,\n QueryThreadsOptions,\n QueryVotesFilters,\n QueryVotesOptions,\n ReactionFilters,\n ReactionResponse,\n ReactionSort,\n ReactivateUserOptions,\n ReactivateUsersOptions,\n ReminderAPIResponse,\n ReviewFlagReportOptions,\n ReviewFlagReportResponse,\n SdkIdentifier,\n SearchAPIResponse,\n SearchMessageSortBase,\n SearchOptions,\n SearchPayload,\n SegmentData,\n SegmentResponse,\n SegmentTargetsResponse,\n SegmentType,\n SendFileAPIResponse,\n SharedLocationResponse,\n SortParam,\n StreamChatOptions,\n SyncOptions,\n SyncResponse,\n TaskResponse,\n TaskStatus,\n TestPushDataInput,\n TestSNSDataInput,\n TestSQSDataInput,\n TokenOrProvider,\n TranslateResponse,\n UnBanUserOptions,\n UpdateChannelTypeRequest,\n UpdateChannelTypeResponse,\n UpdateCommandOptions,\n UpdateCommandResponse,\n UpdateLocationPayload,\n UpdateMessageAPIResponse,\n UpdateMessageOptions,\n UpdatePollAPIResponse,\n UpdatePollOptionAPIResponse,\n UpdateReminderOptions,\n UpdateSegmentData,\n UpsertPushPreferencesResponse,\n UserCustomEvent,\n UserFilters,\n UserOptions,\n UserResponse,\n UserSort,\n VoteSort,\n} from './types';\nimport { ErrorFromResponse } from './types';\nimport { InsightMetrics, postInsights } from './insights';\nimport { Thread } from './thread';\nimport { Moderation } from './moderation';\nimport { ThreadManager } from './thread_manager';\nimport { DEFAULT_QUERY_CHANNELS_MESSAGE_LIST_PAGE_SIZE } from './constants';\nimport { PollManager } from './poll_manager';\nimport type {\n ChannelManagerEventHandlerOverrides,\n ChannelManagerOptions,\n QueryChannelsRequestType,\n} from './channel_manager';\nimport { ChannelManager } from './channel_manager';\nimport { NotificationManager } from './notifications';\nimport { ReminderManager } from './reminders';\nimport { StateStore } from './store';\nimport type { MessageComposer } from './messageComposer';\nimport type { AbstractOfflineDB } from './offline-support';\n\nfunction isString(x: unknown): x is string {\n return typeof x === 'string' || x instanceof String;\n}\n\ntype MessageComposerTearDownFunction = () => void;\n\ntype MessageComposerSetupFunction = ({\n composer,\n}: {\n composer: MessageComposer;\n}) => void | MessageComposerTearDownFunction;\n\nexport type MessageComposerSetupState = {\n /**\n * Each `MessageComposer` runs this function each time its signature changes or\n * whenever you run `MessageComposer.registerSubscriptions`. Function returned\n * from `applyModifications` will be used as a cleanup function - it will be stored\n * and ran before new modification is applied. Cleaning up only the\n * modified parts is the general way to go but if your setup gets a bit\n * complicated, feel free to restore the whole composer with `MessageComposer.restore`.\n */\n setupFunction: MessageComposerSetupFunction | null;\n};\n\nexport class StreamChat {\n private static _instance?: unknown | StreamChat; // type is undefined|StreamChat, unknown is due to TS limitations with statics\n\n _user?: OwnUserResponse | UserResponse;\n appSettingsPromise?: Promise<AppSettingsAPIResponse>;\n activeChannels: {\n [key: string]: Channel;\n };\n threads: ThreadManager;\n polls: PollManager;\n offlineDb?: AbstractOfflineDB;\n notifications: NotificationManager;\n reminders: ReminderManager;\n anonymous: boolean;\n persistUserOnConnectionFailure?: boolean;\n axiosInstance: AxiosInstance;\n baseURL?: string;\n browser: boolean;\n cleaningIntervalRef?: NodeJS.Timeout;\n clientID?: string;\n configs: Configs;\n key: string;\n listeners: Record<string, Array<(event: Event) => void>>;\n logger: Logger;\n /**\n * When network is recovered, we re-query the active channels on client. But in single query, you can recover\n * only 30 channels. So its not guaranteed that all the channels in activeChannels object have updated state.\n * Thus in UI sdks, state recovery is managed by components themselves, they don't rely on js client for this.\n *\n * `recoverStateOnReconnect` parameter can be used in such cases, to disable state recovery within js client.\n * When false, user/consumer of this client will need to make sure all the channels present on UI by\n * manually calling queryChannels endpoint.\n */\n recoverStateOnReconnect?: boolean;\n moderation: Moderation;\n mutedChannels: ChannelMute[];\n mutedUsers: Mute[];\n node: boolean;\n options: StreamChatOptions;\n secret?: string;\n setUserPromise: ConnectAPIResponse | null;\n state: ClientState;\n tokenManager: TokenManager;\n user?: OwnUserResponse | UserResponse;\n userAgent?: string;\n userID?: string;\n wsBaseURL?: string;\n wsConnection: StableWSConnection | null;\n wsFallback?: WSConnectionFallback;\n wsPromise: ConnectAPIResponse | null;\n consecutiveFailures: number;\n insightMetrics: InsightMetrics;\n defaultWSTimeoutWithFallback: number;\n defaultWSTimeout: number;\n sdkIdentifier?: SdkIdentifier;\n deviceIdentifier?: DeviceIdentifier;\n private nextRequestAbortController: AbortController | null = null;\n /**\n * @private\n */\n _messageComposerSetupState = new StateStore<MessageComposerSetupState>({\n setupFunction: null,\n });\n\n /**\n * Initialize a client\n *\n * **Only use constructor for advanced usages. It is strongly advised to use `StreamChat.getInstance()` instead of `new StreamChat()` to reduce integration issues due to multiple WebSocket connections**\n * @param {string} key - the api key\n * @param {string} [secret] - the api secret\n * @param {StreamChatOptions} [options] - additional options, here you can pass custom options to axios instance\n * @param {boolean} [options.browser] - enforce the client to be in browser mode\n * @param {boolean} [options.warmUp] - default to false, if true, client will open a connection as soon as possible to speed up following requests\n * @param {Logger} [options.Logger] - custom logger\n * @param {number} [options.timeout] - default to 3000\n * @param {httpsAgent} [options.httpsAgent] - custom httpsAgent, in node it's default to https.agent()\n * @example <caption>initialize the client in user mode</caption>\n * new StreamChat('api_key')\n * @example <caption>initialize the client in user mode with options</caption>\n * new StreamChat('api_key', { warmUp:true, timeout:5000 })\n * @example <caption>secret is optional and only used in server side mode</caption>\n * new StreamChat('api_key', \"secret\", { httpsAgent: customAgent })\n */\n constructor(key: string, options?: StreamChatOptions);\n constructor(key: string, secret?: string, options?: StreamChatOptions);\n constructor(\n key: string,\n secretOrOptions?: StreamChatOptions | string,\n options?: StreamChatOptions,\n ) {\n // set the key\n this.key = key;\n this.listeners = {};\n this.state = new ClientState({ client: this });\n // a list of channels to hide ws events from\n this.mutedChannels = [];\n this.mutedUsers = [];\n\n this.moderation = new Moderation(this);\n\n this.notifications = options?.notifications ?? new NotificationManager();\n\n // set the secret\n if (secretOrOptions && isString(secretOrOptions)) {\n this.secret = secretOrOptions;\n }\n\n // set the options... and figure out defaults...\n const inputOptions = options\n ? options\n : secretOrOptions && !isString(secretOrOptions)\n ? secretOrOptions\n : {};\n\n this.browser =\n typeof inputOptions.browser !== 'undefined'\n ? inputOptions.browser\n : typeof window !== 'undefined';\n this.node = !this.browser;\n\n this.options = {\n timeout: 3000,\n withCredentials: false, // making sure cookies are not sent\n warmUp: false,\n recoverStateOnReconnect: true,\n disableCache: false,\n wsUrlParams: new URLSearchParams({}),\n ...inputOptions,\n };\n\n if (this.node && !this.options.httpsAgent) {\n this.options.httpsAgent = new https.Agent({\n keepAlive: true,\n keepAliveMsecs: 3000,\n });\n }\n\n this.axiosInstance = axios.create(this.options);\n\n this.setBaseURL(this.options.baseURL || 'https://chat.stream-io-api.com');\n\n if (\n typeof process !== 'undefined' &&\n 'env' in process &&\n process.env.STREAM_LOCAL_TEST_RUN\n ) {\n this.setBaseURL('http://localhost:3030');\n }\n\n if (\n typeof process !== 'undefined' &&\n 'env' in process &&\n process.env.STREAM_LOCAL_TEST_HOST\n ) {\n this.setBaseURL('http://' + process.env.STREAM_LOCAL_TEST_HOST);\n }\n\n // WS connection is initialized when setUser is called\n this.wsConnection = null;\n this.wsPromise = null;\n this.setUserPromise = null;\n // keeps a reference to all the channels that are in use\n this.activeChannels = {};\n\n // mapping between channel groups and configs\n this.configs = {};\n this.anonymous = false;\n this.persistUserOnConnectionFailure = this.options?.persistUserOnConnectionFailure;\n\n // If its a server-side client, then lets initialize the tokenManager, since token will be\n // generated from secret.\n this.tokenManager = new TokenManager(this.secret);\n this.consecutiveFailures = 0;\n this.insightMetrics = new InsightMetrics();\n\n this.defaultWSTimeoutWithFallback = 6 * 1000;\n this.defaultWSTimeout = 15 * 1000;\n\n this.axiosInstance.defaults.paramsSerializer = axiosParamsSerializer;\n\n /**\n * logger function should accept 3 parameters:\n * @param logLevel string\n * @param message string\n * @param extraData object\n *\n * e.g.,\n * const client = new StreamChat('api_key', {}, {\n * logger = (logLevel, message, extraData) => {\n * console.log(message);\n * }\n * })\n *\n * extraData contains tags array attached to log message. Tags can have one/many of following values:\n * 1. api\n * 2. api_request\n * 3. api_response\n * 4. client\n * 5. channel\n * 6. connection\n * 7. event\n *\n * It may also contains some extra data, some examples have been mentioned below:\n * 1. {\n * tags: ['api', 'api_request', 'client'],\n * url: string,\n * payload: object,\n * config: object\n * }\n * 2. {\n * tags: ['api', 'api_response', 'client'],\n * url: string,\n * response: object\n * }\n * 3. {\n * tags: ['api', 'api_response', 'client'],\n * url: string,\n * error: object\n * }\n * 4. {\n * tags: ['event', 'client'],\n * event: object\n * }\n * 5. {\n * tags: ['channel'],\n * channel: object\n * }\n */\n this.logger = isFunction(inputOptions.logger) ? inputOptions.logger : () => null;\n this.recoverStateOnReconnect = this.options.recoverStateOnReconnect;\n this.threads = new ThreadManager({ client: this });\n this.polls = new PollManager({ client: this });\n this.reminders = new ReminderManager({ client: this });\n }\n\n /**\n * Get a client instance\n *\n * This function always returns the same Client instance to avoid issues raised by multiple Client and WS connections\n *\n * **After the first call, the client configuration will not change if the key or options parameters change**\n *\n * @param {string} key - the api key\n * @param {string} [secret] - the api secret\n * @param {StreamChatOptions} [options] - additional options, here you can pass custom options to axios instance\n * @param {boolean} [options.browser] - enforce the client to be in browser mode\n * @param {boolean} [options.warmUp] - default to false, if true, client will open a connection as soon as possible to speed up following requests\n * @param {Logger} [options.Logger] - custom logger\n * @param {number} [options.timeout] - default to 3000\n * @param {httpsAgent} [options.httpsAgent] - custom httpsAgent, in node it's default to https.agent()\n * @example <caption>initialize the client in user mode</caption>\n * StreamChat.getInstance('api_key')\n * @example <caption>initialize the client in user mode with options</caption>\n * StreamChat.getInstance('api_key', { timeout:5000 })\n * @example <caption>secret is optional and only used in server side mode</caption>\n * StreamChat.getInstance('api_key', \"secret\", { httpsAgent: customAgent })\n */\n public static getInstance(key: string, options?: StreamChatOptions): StreamChat;\n public static getInstance(\n key: string,\n secret?: string,\n options?: StreamChatOptions,\n ): StreamChat;\n public static getInstance(\n key: string,\n secretOrOptions?: StreamChatOptions | string,\n options?: StreamChatOptions,\n ): StreamChat {\n if (!StreamChat._instance) {\n if (typeof secretOrOptions === 'string') {\n StreamChat._instance = new StreamChat(key, secretOrOptions, options);\n } else {\n StreamChat._instance = new StreamChat(key, secretOrOptions);\n }\n }\n\n return StreamChat._instance as StreamChat;\n }\n\n setOfflineDBApi(offlineDBInstance: AbstractOfflineDB) {\n if (this.offlineDb) {\n return;\n }\n\n this.offlineDb = offlineDBInstance;\n }\n\n devToken(userID: string) {\n return DevToken(userID);\n }\n\n getAuthType() {\n return this.anonymous ? 'anonymous' : 'jwt';\n }\n\n setBaseURL(baseURL: string) {\n this.baseURL = baseURL;\n this.wsBaseURL = this.baseURL.replace('http', 'ws').replace(':3030', ':8800');\n }\n\n _getConnectionID = () =>\n this.wsConnection?.connectionID || this.wsFallback?.connectionID;\n\n _hasConnectionID = () => Boolean(this._getConnectionID());\n\n public setMessageComposerSetupFunction = (\n setupFunction: MessageComposerSetupState['setupFunction'],\n ) => {\n this._messageComposerSetupState.partialNext({ setupFunction });\n };\n\n /**\n * connectUser - Set the current user and open a WebSocket connection\n *\n * @param {OwnUserResponse | UserResponse} user Data about this user. IE {name: \"john\"}\n * @param {TokenOrProvider} userTokenOrProvider Token or provider\n *\n * @return {ConnectAPIResponse} Returns a promise that resolves when the connection is setup\n */\n connectUser = async (\n user: OwnUserResponse | UserResponse,\n userTokenOrProvider: TokenOrProvider,\n ) => {\n if (!user.id) {\n throw new Error('The \"id\" field on the user is missing');\n }\n\n /**\n * Calling connectUser multiple times is potentially the result of a bad integration, however,\n * If the user id remains the same we don't throw error\n */\n if (this.userID === user.id && this.setUserPromise) {\n console.warn(\n 'Consecutive calls to connectUser is detected, ideally you should only call this function once in your app.',\n );\n return this.setUserPromise;\n }\n\n if (this.userID) {\n throw new Error(\n 'Use client.disconnect() before trying to connect as a different user. connectUser was called twice.',\n );\n }\n\n if (\n (this._isUsingServerAuth() || this.node) &&\n !this.options.allowServerSideConnect\n ) {\n console.warn(\n 'Please do not use connectUser server side. connectUser impacts MAU and concurrent connection usage and thus your bill. If you have a valid use-case, add \"allowServerSideConnect: true\" to the client options to disable this warning.',\n );\n }\n\n // we generate the client id client side\n this.userID = user.id;\n this.anonymous = false;\n\n const setTokenPromise = this._setToken(user, userTokenOrProvider);\n this._setUser(user);\n\n const wsPromise = this.openConnection();\n\n this.setUserPromise = Promise.all([setTokenPromise, wsPromise]).then(\n (result) => result[1], // We only return connection promise;\n );\n\n try {\n return await this.setUserPromise;\n } catch (err) {\n if (this.persistUserOnConnectionFailure) {\n // cleanup client to allow the user to retry connectUser again\n this.closeConnection();\n } else {\n this.disconnectUser();\n }\n throw err;\n }\n };\n\n /**\n * @deprecated Please use connectUser() function instead. Its naming is more consistent with its functionality.\n *\n * setUser - Set the current user and open a WebSocket connection\n *\n * @param {OwnUserResponse | UserResponse} user Data about this user. IE {name: \"john\"}\n * @param {TokenOrProvider} userTokenOrProvider Token or provider\n *\n * @return {ConnectAPIResponse} Returns a promise that resolves when the connection is setup\n */\n setUser = this.connectUser;\n\n _setToken = (user: UserResponse, userTokenOrProvider: TokenOrProvider) =>\n this.tokenManager.setTokenOrProvider(userTokenOrProvider, user);\n\n _setUser(user: OwnUserResponse | UserResponse) {\n /**\n * This one is used by the frontend. This is a copy of the current user object stored on backend.\n * It contains reserved properties and own user properties which are not present in `this._user`.\n */\n this.user = user;\n this.userID = user.id;\n // this one is actually used for requests. This is a copy of current user provided to `connectUser` function.\n this._user = { ...user };\n }\n\n /**\n * Disconnects the websocket connection, without removing the user set on client.\n * client.closeConnection will not trigger default auto-retry mechanism for reconnection. You need\n * to call client.openConnection to reconnect to websocket.\n *\n * This is mainly useful on mobile side. You can only receive push notifications\n * if you don't have active websocket connection.\n * So when your app goes to background, you can call `client.closeConnection`.\n * And when app comes back to foreground, call `client.openConnection`.\n *\n * @param timeout Max number of ms, to wait for close event of websocket, before forcefully assuming succesful disconnection.\n * https://developer.mozilla.org/en-US/docs/Web/API/CloseEvent\n */\n closeConnection = async (timeout?: number) => {\n if (this.cleaningIntervalRef != null) {\n clearInterval(this.cleaningIntervalRef);\n this.cleaningIntervalRef = undefined;\n }\n\n await Promise.all([\n this.wsConnection?.disconnect(timeout),\n this.wsFallback?.disconnect(timeout),\n ]);\n\n this.offlineDb?.executeQuerySafely(\n async (db) => {\n if (this.userID) {\n await db.upsertUserSyncStatus({\n userId: this.userID,\n lastSyncedAt: new Date().toString(),\n });\n }\n },\n { method: 'upsertUserSyncStatus' },\n );\n\n return Promise.resolve();\n };\n\n /**\n * Creates an instance of ChannelManager.\n *\n * @internal\n *\n * @param eventHandlerOverrides - the overrides for event handlers to be used\n * @param options - the options used for the channel manager\n */\n createChannelManager = ({\n eventHandlerOverrides = {},\n options = {},\n queryChannelsOverride,\n }: {\n eventHandlerOverrides?: ChannelManagerEventHandlerOverrides;\n options?: ChannelManagerOptions;\n queryChannelsOverride?: QueryChannelsRequestType;\n }) =>\n new ChannelManager({\n client: this,\n eventHandlerOverrides,\n options,\n queryChannelsOverride,\n });\n\n /**\n * Creates a new WebSocket connection with the current user. Returns empty promise, if there is an active connection\n */\n openConnection = () => {\n if (!this.userID) {\n throw Error(\n 'User is not set on client, use client.connectUser or client.connectAnonymousUser instead',\n );\n }\n\n if (this.wsConnection?.isConnecting && this.wsPromise) {\n this.logger('info', 'client:openConnection() - connection already in progress', {\n tags: ['connection', 'client'],\n });\n return this.wsPromise;\n }\n\n if (\n (this.wsConnection?.isHealthy || this.wsFallback?.isHealthy()) &&\n this._hasConnectionID()\n ) {\n this.logger(\n 'info',\n 'client:openConnection() - openConnection called twice, healthy connection already exists',\n {\n tags: ['connection', 'client'],\n },\n );\n\n return;\n }\n\n this.clientID = `${this.userID}--${randomId()}`;\n this.wsPromise = this.connect();\n this._startCleaning();\n return this.wsPromise;\n };\n\n /**\n * @deprecated Please use client.openConnction instead.\n * @private\n *\n * Creates a new websocket connection with current user.\n */\n _setupConnection = this.openConnection;\n\n /**\n * updateAppSettings - updates application settings\n *\n * @param {AppSettings} options App settings.\n * IE: {\n 'apn_config': {\n 'auth_type': 'token',\n 'auth_key\": fs.readFileSync(\n './apn-push-auth-key.p8',\n 'utf-8',\n ),\n 'key_id': 'keyid',\n 'team_id': 'teamid',\n 'notification_template\": 'notification handlebars template',\n 'bundle_id': 'com.apple.your.app',\n 'development': true\n },\n 'firebase_config': {\n 'server_key': 'server key from fcm',\n 'notification_template': 'notification handlebars template',\n 'data_template': 'data handlebars template',\n 'apn_template': 'apn notification handlebars template under v2'\n },\n 'webhook_url': 'https://acme.com/my/awesome/webhook/',\n 'event_hooks': [\n {\n 'hook_type': 'webhook',\n 'enabled': true,\n 'event_types': ['message.new'],\n 'webhook_url': 'https://acme.com/my/awesome/webhook/'\n },\n {\n 'hook_type': 'sqs',\n 'enabled': true,\n 'event_types': ['message.new'],\n 'sqs_url': 'https://sqs.us-east-1.amazonaws.com/1234567890/my-queue',\n 'sqs_auth_type': 'key',\n 'sqs_key': 'my-access-key',\n 'sqs_secret': 'my-secret-key'\n }\n ]\n }\n */\n async updateAppSettings(options: AppSettings) {\n const apn_config = options.apn_config;\n if (apn_config?.p12_cert) {\n options = {\n ...options,\n apn_config: {\n ...apn_config,\n p12_cert: Buffer.from(apn_config.p12_cert).toString('base64'),\n },\n };\n }\n return await this.patch<APIResponse>(this.baseURL + '/app', options);\n }\n\n _normalizeDate = (before: Date | string | null): string | null => {\n if (before instanceof Date) {\n before = before.toISOString();\n }\n\n if (before === '') {\n throw new Error(\n \"Don't pass blank string for since, use null instead if resetting the token revoke\",\n );\n }\n\n return before;\n };\n\n /**\n * Revokes all tokens on application level issued before given time\n */\n async revokeTokens(before: Date | string | null) {\n return await this.updateAppSettings({\n revoke_tokens_issued_before: this._normalizeDate(before),\n });\n }\n\n /**\n * Revokes token for a user issued before given time\n */\n async revokeUserToken(userID: string, before?: Date | string | null) {\n return await this.revokeUsersToken([userID], before);\n }\n\n /**\n * Revokes tokens for a list of users issued before given time\n */\n async revokeUsersToken(userIDs: string[], before?: Date | string | null) {\n if (before === undefined) {\n before = new Date().toISOString();\n } else {\n before = this._normalizeDate(before);\n }\n\n const users: PartialUserUpdate[] = [];\n for (const userID of userIDs) {\n users.push({\n id: userID,\n set: <Partial<UserResponse>>{\n revoke_tokens_issued_before: before,\n },\n });\n }\n\n return await this.partialUpdateUsers(users);\n }\n\n /**\n * getAppSettings - retrieves application settings\n */\n async getAppSettings() {\n this.appSettingsPromise = this.get<AppSettingsAPIResponse>(this.baseURL + '/app');\n return await this.appSettingsPromise;\n }\n\n /**\n * testPushSettings - Tests the push settings for a user with a random chat message and the configured push templates\n *\n * @param {string} userID User ID. If user has no devices, it will error\n * @param {TestPushDataInput} [data] Overrides for push templates/message used\n * IE: {\n messageID: 'id-of-message', // will error if message does not exist\n apnTemplate: '{}', // if app doesn't have apn configured it will error\n firebaseTemplate: '{}', // if app doesn't have firebase configured it will error\n firebaseDataTemplate: '{}', // if app doesn't have firebase configured it will error\n skipDevices: true, // skip config/device checks and sending to real devices\n pushProviderName: 'staging' // one of your configured push providers\n pushProviderType: 'apn' // one of supported provider types\n }\n */\n async testPushSettings(userID: string, data: TestPushDataInput = {}) {\n return await this.post<CheckPushResponse>(this.baseURL + '/check_push', {\n user_id: userID,\n ...(data.messageID ? { message_id: data.messageID } : {}),\n ...(data.apnTemplate ? { apn_template: data.apnTemplate } : {}),\n ...(data.firebaseTemplate ? { firebase_template: data.firebaseTemplate } : {}),\n ...(data.firebaseDataTemplate\n ? { firebase_data_template: data.firebaseDataTemplate }\n : {}),\n ...(data.skipDevices ? { skip_devices: true } : {}),\n ...(data.pushProviderName ? { push_provider_name: data.pushProviderName } : {}),\n ...(data.pushProviderType ? { push_provider_type: data.pushProviderType } : {}),\n });\n }\n\n /**\n * testSQSSettings - Tests that the given or configured SQS configuration is valid\n *\n * @param {TestSQSDataInput} [data] Overrides SQS settings for testing if needed\n * IE: {\n sqs_key: 'auth_key',\n sqs_secret: 'auth_secret',\n sqs_url: 'url_to_queue',\n }\n */\n async testSQSSettings(data: TestSQSDataInput = {}) {\n return await this.post<CheckSQSResponse>(this.baseURL + '/check_sqs', data);\n }\n\n /**\n * testSNSSettings - Tests that the given or configured SNS configuration is valid\n *\n * @param {TestSNSDataInput} [data] Overrides SNS settings for testing if needed\n * IE: {\n sns_key: 'auth_key',\n sns_secret: 'auth_secret',\n sns_topic_arn: 'topic_to_publish_to',\n }\n */\n async testSNSSettings(data: TestSNSDataInput = {}) {\n return await this.post<CheckSNSResponse>(this.baseURL + '/check_sns', data);\n }\n\n /**\n * Disconnects the websocket and removes the user from client.\n *\n * @param timeout Max number of ms, to wait for close event of websocket, before forcefully assuming successful disconnection.\n * https://developer.mozilla.org/en-US/docs/Web/API/CloseEvent\n */\n disconnectUser = (timeout?: number) => {\n this.logger('info', 'client:disconnect() - Disconnecting the client', {\n tags: ['connection', 'client'],\n });\n\n // remove the user specific fields\n delete this.user;\n delete this._user;\n delete this.userID;\n\n this.anonymous = false;\n\n const closePromise = this.closeConnection(timeout);\n\n for (const channel of Object.values(this.activeChannels)) {\n channel._disconnect();\n }\n // ensure we no longer return inactive channels\n this.activeChannels = {};\n // reset client state\n this.state = new ClientState({ client: this });\n // reset thread manager\n this.threads.resetState();\n\n // Since we wipe all user data already, we should reset token manager as well\n closePromise\n .finally(() => {\n this.tokenManager.reset();\n })\n .catch((err) => console.error(err));\n\n // close the WS connection\n return closePromise;\n };\n\n /**\n *\n * @deprecated Please use client.disconnectUser instead.\n *\n * Disconnects the websocket and removes the user from client.\n */\n disconnect = this.disconnectUser;\n\n /**\n * connectAnonymousUser - Set an anonymous user and open a WebSocket connection\n */\n connectAnonymousUser = () => {\n if (\n (this._isUsingServerAuth() || this.node) &&\n !this.options.allowServerSideConnect\n ) {\n console.warn(\n 'Please do not use connectUser server side. connectUser impacts MAU and concurrent connection usage and thus your bill. If you have a valid use-case, add \"allowServerSideConnect: true\" to the client options to disable this warning.',\n );\n }\n\n this.anonymous = true;\n this.userID = randomId();\n const anonymousUser = {\n id: this.userID,\n anon: true,\n } as UserResponse;\n\n this._setToken(anonymousUser, '');\n this._setUser(anonymousUser);\n\n return this._setupConnection();\n };\n\n /**\n * @deprecated Please use connectAnonymousUser. Its naming is more consistent with its functionality.\n */\n setAnonymousUser = this.connectAnonymousUser;\n\n /**\n * setGuestUser - Setup a temporary guest user\n *\n * @param {UserResponse} user Data about this user. IE {name: \"john\"}\n *\n * @return {ConnectAPIResponse} Returns a promise that resolves when the connection is setup\n */\n async setGuestUser(user: UserResponse) {\n let response: { access_token: string; user: UserResponse } | undefined;\n this.anonymous = true;\n try {\n response = await this.post<\n APIResponse & {\n access_token: string;\n user: UserResponse;\n }\n >(this.baseURL + '/guest', { user });\n } catch (e) {\n this.anonymous = false;\n throw e;\n }\n this.anonymous = false;\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n const { created_at, updated_at, last_active, online, ...guestUser } = response.user;\n return await this.connectUser(guestUser as UserResponse, response.access_token);\n }\n\n /**\n * createToken - Creates a token to authenticate this user. This function is used server side.\n * The resulting token should be passed to the client side when the users registers or logs in.\n *\n * @param {string} userID The User ID\n * @param {number} [exp] The expiration time for the token expressed in the number of seconds since the epoch\n *\n * @return {string} Returns a token\n */\n createToken(userID: string, exp?: number, iat?: number) {\n if (this.secret == null) {\n throw Error(`tokens can only be created server-side using the API Secret`);\n }\n const extra: { exp?: number; iat?: number } = {};\n\n if (exp) {\n extra.exp = exp;\n }\n\n if (iat) {\n extra.iat = iat;\n }\n\n return JWTUserToken(this.secret, userID, extra, {});\n }\n\n /**\n * on - Listen to events on all channels and users your watching\n *\n * client.on('message.new', event => {console.log(\"my new message\", event, channel.state.messages)})\n * or\n * client.on(event => {console.log(event.type)})\n *\n * @param {EventHandler | string} callbackOrString The event type to listen for (optional)\n * @param {EventHandler} [callbackOrNothing] The callback to call\n *\n * @return {{ unsubscribe: () => void }} Description\n */\n on(callback: EventHandler): { unsubscribe: () => void };\n on(eventType: string, callback: EventHandler): { unsubscribe: () => void };\n on(\n callbackOrString: EventHandler | string,\n callbackOrNothing?: EventHandler,\n ): { unsubscribe: () => void } {\n const key = callbackOrNothing ? (callbackOrString as string) : 'all';\n const callback = callbackOrNothing\n ? callbackOrNothing\n : (callbackOrString as EventHandler);\n if (!(key in this.listeners)) {\n this.listeners[key] = [];\n }\n this.logger('info', `Attaching listener for ${key} event`, {\n tags: ['event', 'client'],\n });\n this.listeners[key].push(callback);\n return {\n unsubscribe: () => {\n this.logger('info', `Removing listener for ${key} event`, {\n tags: ['event', 'client'],\n });\n this.listeners[key] = this.listeners[key].filter((el) => el !== callback);\n },\n };\n }\n\n /**\n * off - Remove the event handler\n *\n */\n off(callback: EventHandler): void;\n off(eventType: string, callback: EventHandler): void;\n off(callbackOrString: EventHandler | string, callbackOrNothing?: EventHandler) {\n const key = callbackOrNothing ? (callbackOrString as string) : 'all';\n const callback = callbackOrNothing\n ? callbackOrNothing\n : (callbackOrString as EventHandler);\n if (!(key in this.listeners)) {\n this.listeners[key] = [];\n }\n\n this.logger('info', `Removing listener for ${key} event`, {\n tags: ['event', 'client'],\n });\n this.listeners[key] = this.listeners[key].filter((value) => value !== callback);\n }\n\n _logApiRequest(\n type: string,\n url: string,\n data: unknown,\n config: AxiosRequestConfig & {\n config?: AxiosRequestConfig & { maxBodyLength?: number };\n },\n ) {\n this.logger('info', `client: ${type} - Request - ${url}`, {\n tags: ['api', 'api_request', 'client'],\n url,\n payload: data,\n config,\n });\n }\n\n _logApiResponse<T>(type: string, url: string, response: AxiosResponse<T>) {\n this.logger(\n 'info',\n `client:${type} - Response - url: ${url} > status ${response.status}`,\n {\n tags: ['api', 'api_response', 'client'],\n url,\n response,\n },\n );\n }\n\n _logApiError(type: string, url: string, error: unknown) {\n this.logger('error', `client:${type} - Error - url: ${url}`, {\n tags: ['api', 'api_response', 'client'],\n url,\n error,\n });\n }\n\n doAxiosRequest = async <T>(\n type: string,\n url: string,\n data?: unknown,\n options: AxiosRequestConfig & {\n config?: AxiosRequestConfig & { maxBodyLength?: number };\n } = {},\n ): Promise<T> => {\n await this.tokenManager.tokenReady();\n const requestConfig = this._enrichAxiosOptions(options);\n try {\n let response: AxiosResponse<T>;\n this._logApiRequest(type, url, data, requestConfig);\n switch (type) {\n case 'get':\n response = await this.axiosInstance.get(url, requestConfig);\n break;\n case 'delete':\n response = await this.axiosInstance.delete(url, requestConfig);\n break;\n case 'post':\n response = await this.axiosInstance.post(url, data, requestConfig);\n break;\n case 'postForm':\n response = await this.axiosInstance.postForm(url, data, requestConfig);\n break;\n case 'put':\n response = await this.axiosInstance.put(url, data, requestConfig);\n break;\n case 'patch':\n response = await this.axiosInstance.patch(url, data, requestConfig);\n break;\n case 'options':\n response = await this.axiosInstance.options(url, requestConfig);\n break;\n default:\n throw new Error('Invalid request type');\n }\n this._logApiResponse<T>(type, url, response);\n this.consecutiveFailures = 0;\n return this.handleResponse(response);\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n } catch (e: any /**TODO: generalize error types */) {\n e.client_request_id = requestConfig.headers?.['x-client-request-id'];\n this._logApiError(type, url, e);\n this.consecutiveFailures += 1;\n if (e.response) {\n /** connection_fallback depends on this token expiration logic */\n if (\n e.response.data.code === chatCodes.TOKEN_EXPIRED &&\n !this.tokenManager.isStatic()\n ) {\n if (this.consecutiveFailures > 1) {\n await sleep(retryInterval(this.consecutiveFailures));\n }\n this.tokenManager.loadToken();\n return await this.doAxiosRequest<T>(type, url, data, options);\n }\n return this.handleResponse(e.response);\n } else {\n throw e as AxiosError<APIErrorResponse>;\n }\n }\n };\n\n get<T>(url: string, params?: AxiosRequestConfig['params']) {\n return this.doAxiosRequest<T>('get', url, null, { params });\n }\n\n put<T>(url: string, data?: unknown) {\n return this.doAxiosRequest<T>('put', url, data);\n }\n\n post<T>(url: string, data?: unknown) {\n return this.doAxiosRequest<T>('post', url, data);\n }\n\n patch<T>(url: string, data?: unknown) {\n return this.doAxiosRequest<T>('patch', url, data);\n }\n\n delete<T>(url: string, params?: AxiosRequestConfig['params']) {\n return this.doAxiosRequest<T>('delete', url, null, { params });\n }\n\n sendFile(\n url: string,\n uri: string | NodeJS.ReadableStream | Buffer | File,\n name?: string,\n contentType?: string,\n user?: UserResponse,\n ) {\n const data = addFileToFormData(uri, name, contentType || 'multipart/form-data');\n if (user != null) data.append('user', JSON.stringify(user));\n\n return this.doAxiosRequest<SendFileAPIResponse>('postForm', url, data, {\n headers: data.getHeaders ? data.getHeaders() : {}, // node vs browser\n config: {\n timeout: 0,\n maxContentLength: Infinity,\n maxBodyLength: Infinity,\n },\n });\n }\n\n errorFromResponse(response: AxiosResponse<APIErrorResponse>) {\n const message =\n typeof response.data.code !== 'undefined'\n ? `StreamChat error code ${response.data.code}: ${response.data.message}`\n : `StreamChat error HTTP code: ${response.status}`;\n\n return new ErrorFromResponse<APIErrorResponse>(message, {\n code: response.data.code ?? null,\n response,\n status: response.status,\n });\n }\n\n handleResponse<T>(response: AxiosResponse<T>) {\n const data = response.data;\n if (isErrorResponse(response)) {\n throw this.errorFromResponse(response);\n }\n return data;\n }\n\n dispatchEvent = (event: Event) => {\n if (!event.received_at) event.received_at = new Date();\n\n // client event handlers\n const postListenerCallbacks = this._handleClientEvent(event);\n\n // channel event handlers\n const cid = event.cid;\n const channel = cid ? this.activeChannels[cid] : undefined;\n if (channel) {\n channel._handleChannelEvent(event);\n }\n\n this._callClientListeners(event);\n\n if (channel) {\n channel._callChannelListeners(event);\n }\n\n postListenerCallbacks.forEach((c) => c());\n\n this.offlineDb?.executeQuerySafely((db) => db.handleEvent({ event }), {\n method: `handleEvent;${event.type}`,\n });\n };\n\n handleEvent = (messageEvent: WebSocket.MessageEvent) => {\n // dispatch the event to the channel listeners\n const jsonString = messageEvent.data as string;\n const event = JSON.parse(jsonString) as Event;\n this.dispatchEvent(event);\n };\n\n /**\n * Updates the members, watchers and read references of the currently active channels that contain this user\n *\n * @param {UserResponse} user\n */\n _updateMemberWatcherReferences = (user: UserResponse) => {\n const refMap = this.state.userChannelReferences[user.id] || {};\n for (const channelID in refMap) {\n const channel = this.activeChannels[channelID];\n if (channel?.state) {\n if (channel.state.members[user.id]) {\n channel.state.members[user.id].user = user;\n }\n if (channel.state.watchers[user.id]) {\n channel.state.watchers[user.id] = user;\n }\n if (channel.state.read[user.id]) {\n channel.state.read[user.id].user = user;\n }\n }\n }\n };\n\n /**\n * @deprecated Please _updateMemberWatcherReferences instead.\n * @private\n */\n _updateUserReferences = this._updateMemberWatcherReferences;\n\n /**\n * @private\n *\n * Updates the messages from the currently active channels that contain this user,\n * with updated user object.\n *\n * @param {UserResponse} user\n */\n _updateUserMessageReferences = (user: UserResponse) => {\n const refMap = this.state.userChannelReferences[user.id] || {};\n\n for (const channelID in refMap) {\n const channel = this.activeChannels[channelID];\n\n if (!channel) continue;\n\n const state = channel.state;\n\n /** update the messages from this user. */\n state?.updateUserMessages(user);\n }\n };\n\n /**\n * @private\n *\n * Deletes the messages from the currently active channels that contain this user\n *\n * If hardDelete is true, all the content of message will be stripped down.\n * Otherwise, only 'message.type' will be set as 'deleted'.\n *\n * @param {UserResponse} user\n * @param {boolean} hardDelete\n */\n _deleteUserMessageReference = (\n user: UserResponse,\n hardDelete = false,\n deletedAt?: LocalMessage['deleted_at'],\n ) => {\n const refMap = this.state.userChannelReferences[user.id] || {};\n\n for (const channelID in refMap) {\n const channel = this.activeChannels[channelID];\n if (channel) {\n const state = channel.state;\n\n /** deleted the messages from this user. */\n state?.deleteUserMessages(user, hardDelete, deletedAt);\n }\n }\n };\n\n /**\n * @private\n *\n * Handle following user related events:\n * - user.presence.changed\n * - user.updated\n * - user.deleted\n *\n * @param {Event} event\n */\n _handleUserEvent = (event: Event) => {\n if (!event.user) {\n return;\n }\n\n /** update the client.state with any changes to users */\n if (event.type === 'user.presence.changed' || event.type === 'user.updated') {\n if (event.user.id === this.userID) {\n const user = { ...this.user } as NonNullable<StreamChat['user']>;\n const _user = { ...this._user } as NonNullable<StreamChat['_user']>;\n\n // Remove deleted properties from user objects.\n for (const key in this.user) {\n if (key in event.user || isOwnUserBaseProperty(key)) {\n continue;\n }\n\n const deleteKey = key as keyof typeof user;\n\n delete user[deleteKey];\n delete _user[deleteKey];\n }\n\n /** Updating only available properties in _user object. */\n for (const key in _user) {\n const updateKey = key as keyof typeof _user;\n\n if (updateKey in event.user) {\n // @ts-expect-error it has an issue with this, not sure why\n _user[updateKey] = event.user[updateKey];\n }\n }\n\n this._user = _user;\n this.user = { ...user, ...event.user };\n }\n\n this.state.updateUser(event.user);\n this._updateMemberWatcherReferences(event.user);\n }\n\n if (event.type === 'user.updated') {\n this._updateUserMessageReferences(event.user);\n }\n\n if (\n event.type === 'user.deleted' &&\n event.user.deleted_at &&\n (event.mark_messages_deleted || event.hard_delete)\n ) {\n this._deleteUserMessageReference(\n event.user,\n event.hard_delete,\n event.user.deleted_at ? new Date(event.user.deleted_at) : null,\n );\n }\n };\n\n _handleClientEvent(event: Event) {\n // eslint-disable-next-line @typescript-eslint/no-this-alias\n const client = this;\n const postListenerCallbacks = [];\n this.logger(\n 'info',\n `client:_handleClientEvent - Received event of type { ${event.type} }`,\n {\n tags: ['event', 'client'],\n event,\n },\n );\n\n if (\n event.type === 'user.presence.changed' ||\n event.type === 'user.updated' ||\n event.type === 'user.deleted'\n ) {\n this._handleUserEvent(event);\n }\n\n if (event.type === 'user.messages.deleted' && !event.cid && event.user) {\n this._deleteUserMessageReference(\n event.user,\n event.hard_delete,\n event.created_at ? new Date(event.created_at) : null,\n );\n }\n\n if (event.type === 'health.check' && event.me) {\n client.user = event.me;\n client.state.updateUser(event.me);\n client.mutedChannels = event.me.channel_mutes;\n client.mutedUsers = event.me.mutes;\n }\n\n if (event.channel && event.type === 'notification.message_new') {\n const { channel } = event;\n this._addChannelConfig(channel);\n }\n\n if (event.type === 'notification.channel_mutes_updated' && event.me?.channel_mutes) {\n this.mutedChannels = event.me.channel_mutes;\n }\n\n if (event.type === 'notification.mutes_updated' && event.me?.mutes) {\n this.mutedUsers = event.me.mutes;\n }\n\n if (event.type === 'notification.mark_read' && event.unread_channels === 0) {\n const activeChannelKeys = Object.keys(this.activeChannels);\n activeChannelKeys.forEach(\n (activeChannelKey) =>\n (this.activeChannels[activeChannelKey].state.unreadCount = 0),\n );\n }\n\n if (\n (event.type === 'channel.deleted' ||\n event.type === 'notification.channel_deleted') &&\n event.cid\n ) {\n const { cid } = event;\n client.state.deleteAllChannelReference(cid);\n this.activeChannels[event.cid]?._disconnect();\n\n postListenerCallbacks.push(() => {\n if (!cid) return;\n\n delete this.activeChannels[cid];\n });\n }\n\n return postListenerCallbacks;\n }\n\n _muteStatus(cid: string) {\n let muteStatus;\n for (let i = 0; i < this.mutedChannels.length; i++) {\n const mute = this.mutedChannels[i];\n if (mute.channel?.cid === cid) {\n muteStatus = {\n muted: mute.expires\n ? new Date(mute.expires).getTime() > new Date().getTime()\n : true,\n createdAt: mute.created_at ? new Date(mute.created_at) : new Date(),\n expiresAt: mute.expires ? new Date(mute.expires) : null,\n };\n break;\n }\n }\n\n if (muteStatus) {\n return muteStatus;\n }\n\n return {\n muted: false,\n createdAt: null,\n expiresAt: null,\n };\n }\n\n _callClientListeners = (event: Event) => {\n // eslint-disable-next-line @typescript-eslint/no-this-alias\n const client = this;\n // gather and call the listeners\n const listeners: Array<(event: Event) => void> = [];\n if (client.listeners.all) {\n listeners.push(...client.listeners.all);\n }\n if (client.listeners[event.type]) {\n listeners.push(...client.listeners[event.type]);\n }\n\n // call the event and send it to the listeners\n for (const listener of listeners) {\n listener(event);\n }\n };\n\n recoverState = async () => {\n this.logger(\n 'info',\n `client:recoverState() - Start of recoverState with connectionID ${this._getConnectionID()}`,\n {\n tags: ['connection'],\n },\n );\n\n const cids = Object.keys(this.activeChannels);\n if (cids.length && this.recoverStateOnReconnect) {\n this.logger(\n 'info',\n `client:recoverState() - Start the querying of ${cids.length} channels`,\n {\n tags: ['connection', 'client'],\n },\n );\n\n await this.queryChannels(\n { cid: { $in: cids } } as ChannelFilters,\n { last_message_at: -1 },\n { limit: 30 },\n );\n\n this.logger('info', 'client:recoverState() - Querying channels finished', {\n tags: ['connection', 'client'],\n });\n this.dispatchEvent({\n type: 'connection.recovered',\n } as Event);\n } else {\n this.dispatchEvent({\n type: 'connection.recovered',\n } as Event);\n }\n\n this.wsPromise = Promise.resolve();\n this.setUserPromise = Promise.resolve();\n };\n\n /**\n * @private\n */\n async connect() {\n if (!this.userID || !this._user) {\n throw Error(\n 'Call connectUser or connectAnonymousUser before starting the connection',\n );\n }\n if (!this.wsBaseURL) {\n throw Error('Websocket base url not set');\n }\n if (!this.clientID) {\n throw Error('clientID is not set');\n }\n\n if (!this.wsConnection && (this.options.warmUp || this.options.enableInsights)) {\n this._sayHi();\n }\n // The StableWSConnection handles all the reconnection logic.\n if (this.options.wsConnection && this.node) {\n // Intentionally avoiding adding ts generics on wsConnection in options since its only useful for unit test purpose.\n (this.options.wsConnection as unknown as StableWSConnection).setClient(this);\n this.wsConnection = this.options.wsConnection as unknown as StableWSConnection;\n } else {\n this.wsConnection = new StableWSConnection({\n client: this,\n });\n }\n\n try {\n // if fallback is used before, continue using it instead of waiting for WS to fail\n if (this.wsFallback) {\n return await this.wsFallback.connect();\n }\n\n // if WSFallback is enabled, ws connect should timeout faster so fallback can try\n return await this.wsConnection.connect(\n this.options.enableWSFallback\n ? this.defaultWSTimeoutWithFallback\n : this.defaultWSTimeout,\n );\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n } catch (error: any) {\n // run fallback only if it's WS/Network error and not a normal API error\n // make sure browser is online before even trying the longpoll\n if (this.options.enableWSFallback && isWSFailure(error) && isOnline()) {\n this.logger('info', 'client:connect() - WS failed, fallback to longpoll', {\n tags: ['connection', 'client'],\n });\n this.dispatchEvent({ type: 'transport.changed', mode: 'longpoll' });\n\n this.wsConnection._destroyCurrentWSConnection();\n this.wsConnection.disconnect().then(); // close WS so no retry\n this.wsFallback = new WSConnectionFallback({\n client: this,\n });\n return await this.wsFallback.connect();\n }\n\n throw error;\n }\n }\n\n /**\n * Check the connectivity with server for warmup purpose.\n *\n * @private\n */\n _sayHi() {\n const client_request_id = randomId();\n const opts = { headers: { 'x-client-request-id': client_request_id } };\n this.doAxiosRequest('get', this.baseURL + '/hi', null, opts).catch((e) => {\n if (this.options.enableInsights) {\n postInsights('http_hi_failed', {\n api_key: this.key,\n err: e,\n client_request_id,\n });\n }\n });\n }\n\n /**\n * queryUsers - Query users and watch user presence\n *\n * @param {UserFilters} filterConditions MongoDB style filter conditions\n * @param {UserSort} sort Sort options, for instance [{last_active: -1}].\n * When using multiple fields, make sure you use array of objects to guarantee field order, for instance [{last_active: -1}, {created_at: 1}]\n * @param {UserOptions} options Option object, {presence: true}\n *\n * @return {Promise<{ users: Array<UserResponse> }>} User Query Response\n */\n async queryUsers(\n filterConditions: UserFilters,\n sort: UserSort = [],\n options: UserOptions = {},\n ) {\n const defaultOptions = {\n presence: false,\n };\n\n // Make sure we wait for the connect promise if there is a pending one\n await this.wsPromise;\n\n if (!this._hasConnectionID()) {\n defaultOptions.presence = false;\n }\n\n // Return a list of users\n const data = await this.get<APIResponse & { users: Array<UserResponse> }>(\n this.baseURL + '/users',\n {\n payload: {\n filter_conditions: filterConditions,\n sort: normalizeQuerySort(sort),\n ...defaultOptions,\n ...options,\n },\n },\n );\n\n this.state.updateUsers(data.users);\n\n return data;\n }\n\n /**\n * queryBannedUsers - Query user bans\n *\n * @param {BannedUsersFilters} filterConditions MongoDB style filter conditions\n * @param {BannedUsersSort} sort Sort options [{created_at: 1}].\n * @param {BannedUsersPaginationOptions} options Option object, {limit: 10, offset:0, exclude_expired_bans: true}\n *\n * @return {Promise<BannedUsersResponse>} Ban Query Response\n */\n async queryBannedUsers(\n filterConditions: BannedUsersFilters = {},\n sort: BannedUsersSort = [],\n options: BannedUsersPaginationOptions = {},\n ) {\n // Return a list of user bans\n return await this.get<BannedUsersResponse>(this.baseURL + '/query_banned_users', {\n payload: {\n filter_conditions: filterConditions,\n sort: normalizeQuerySort(sort),\n ...options,\n },\n });\n }\n\n /**\n * queryMessageFlags - Query message flags\n *\n * @param {MessageFlagsFilters} filterConditions MongoDB style filter conditions\n * @param {MessageFlagsPaginationOptions} options Option object, {limit: 10, offset:0}\n *\n * @return {Promise<MessageFlagsResponse>} Message Flags Response\n */\n async queryMessageFlags(\n filterConditions: MessageFlagsFilters = {},\n options: MessageFlagsPaginationOptions = {},\n ) {\n // Return a list of message flags\n return await this.get<MessageFlagsResponse>(\n this.baseURL + '/moderation/flags/message',\n {\n payload: { filter_conditions: filterConditions, ...options },\n },\n );\n }\n\n /**\n * queryChannelsRequest - Queries channels and returns the raw response\n *\n * @param {ChannelFilters} filterConditions object MongoDB style filters\n * @param {ChannelSort} [sort] Sort options, for instance {created_at: -1}.\n * When using multiple fields, make sure you use array of objects to guarantee field order, for instance [{last_updated: -1}, {created_at: 1}]\n * @param {ChannelOptions} [options] Options object\n *\n * @return {Promise<Array<ChannelAPIResponse>>} search channels response\n */\n async queryChannelsRequest(\n filterConditions: ChannelFilters,\n sort: ChannelSort = [],\n options: ChannelOptions = {},\n ) {\n const defaultOptions: ChannelOptions = {\n state: true,\n watch: true,\n presence: false,\n };\n\n // Make sure we wait for the connect promise if there is a pending one\n await this.wsPromise;\n if (!this._hasConnectionID()) {\n defaultOptions.watch = false;\n }\n\n // Return a list of channels\n const payload = {\n filter_conditions: filterConditions,\n sort: normalizeQuerySort(sort),\n ...defaultOptions,\n ...options,\n };\n\n const data = await this.post<QueryChannelsAPIResponse>(\n this.baseURL + '/channels',\n payload,\n );\n\n return data.channels;\n }\n\n /**\n * queryChannels - Query channels\n *\n * @param {ChannelFilters} filterConditions object MongoDB style filters\n * @param {ChannelSort} [sort] Sort options, for instance {created_at: -1}.\n * When using multiple fields, make sure you use array of objects to guarantee field order, for instance [{last_updated: -1}, {created_at: 1}]\n * @param {ChannelOptions} [options] Options object\n * @param {ChannelStateOptions} [stateOptions] State options object. These options will only be used for state management and won't be sent in the request.\n * - stateOptions.skipInitialization - Skips the initialization of the state for the channels matching the ids in the list.\n * - stateOptions.skipHydration - Skips returning the channels as instances of the Channel class and rather returns the raw query response.\n *\n * @return {Promise<Array<Channel>>} search channels response\n */\n async queryChannels(\n filterConditions: ChannelFilters,\n sort: ChannelSort = [],\n options: ChannelOptions = {},\n stateOptions: ChannelStateOptions = {},\n ) {\n const channels = await this.queryChannelsRequest(filterConditions, sort, options);\n\n this.dispatchEvent({\n type: 'channels.queried',\n queriedChannels: {\n channels,\n isLatestMessageSet: true,\n },\n });\n if (channels?.length && this.offlineDb?.upsertChannels) {\n await this.offlineDb.upsertChannels({\n channels,\n isLatestMessagesSet: true,\n });\n }\n\n return this.hydrateActiveChannels(channels, stateOptions, options);\n }\n\n /**\n * queryReactions - Query reactions\n *\n * @param {ReactionFilters} filter object MongoDB style filters\n * @param {ReactionSort} [sort] Sort options, for instance {created_at: -1}.\n * @param {QueryReactionsOptions} [options] Pagination object\n *\n * @return {Promise<{ QueryReactionsAPIResponse } search channels response\n */\n async queryReactions(\n messageID: string,\n filter: ReactionFilters,\n sort: ReactionSort = [],\n options: QueryReactionsOptions = {},\n ) {\n const payload = {\n filter,\n sort: normalizeQuerySort(sort),\n ...options,\n };\n\n if (this.offlineDb?.getReactions && !options.next) {\n try {\n const reactionsFromDb = await this.offlineDb.getReactions({\n messageId: messageID,\n filters: filter,\n sort,\n limit: options.limit,\n });\n\n if (reactionsFromDb) {\n this.dispatchEvent({\n type: 'offline_reactions.queried',\n offlineReactions: reactionsFromDb as ReactionResponse[],\n });\n }\n } catch (e) {\n this.logger('warn', 'An error has occurred while querying offline reactions', {\n error: e,\n });\n }\n }\n\n // Make sure we wait for the connect promise if there is a pending one\n await this.wsPromise;\n\n return await this.post<QueryReactionsAPIResponse>(\n this.baseURL + '/messages/' + encodeURIComponent(messageID) + '/reactions',\n payload,\n );\n }\n\n hydrateActiveChannels(\n channelsFromApi: ChannelAPIResponse[] = [],\n stateOptions: ChannelStateOptions = {},\n queryChannelsOptions?: ChannelOptions,\n ) {\n const { skipInitialization, offlineMode = false } = stateOptions;\n const channels: Channel[] = [];\n\n for (const channelState of channelsFromApi) {\n this._addChannelConfig(channelState.channel);\n const c = this.channel(channelState.channel.type, channelState.channel.id);\n c.data = channelState.channel;\n c.offlineMode = offlineMode;\n c.initialized = !offlineMode;\n c.push_preferences = channelState.push_preferences;\n\n let updatedMessagesSet;\n if (skipInitialization === undefined) {\n const { messageSet } = c._initializeState(channelState, 'latest');\n updatedMessagesSet = messageSet;\n } else if (!skipInitialization.includes(channelState.channel.id)) {\n c.state.clearMessages();\n const { messageSet } = c._initializeState(channelState, 'latest');\n updatedMessagesSet = messageSet;\n }\n\n if (updatedMessagesSet) {\n updatedMessagesSet.pagination = {\n ...updatedMessagesSet.pagination,\n ...messageSetPagination({\n parentSet: updatedMessagesSet,\n requestedPageSize:\n queryChannelsOptions?.message_limit ||\n DEFAULT_QUERY_CHANNELS_MESSAGE_LIST_PAGE_SIZE,\n returnedPage: channelState.messages,\n logger: this.logger,\n }),\n };\n this.polls.hydratePollCache(channelState.messages, true);\n this.reminders.hydrateState(channelState.messages);\n }\n\n c.messageComposer.initStateFromChannelResponse(channelState);\n\n channels.push(c);\n }\n\n return channels;\n }\n\n /**\n * search - Query messages\n *\n * @param {ChannelFilters} filterConditions MongoDB style filter conditions\n * @param {MessageFilters | string} query search query or object MongoDB style filters\n * @param {SearchOptions} [options] Option object, {user_id: 'tommaso'}\n *\n * @return {Promise<SearchAPIResponse>} search messages response\n */\n async search(\n filterConditions: ChannelFilters,\n query: string | MessageFilters,\n options: SearchOptions = {},\n ) {\n if (options.offset && options.next) {\n throw Error(`Cannot specify offset with next`);\n }\n const payload: SearchPayload = {\n filter_conditions: filterConditions,\n ...options,\n sort: options.sort\n ? normalizeQuerySort<SearchMessageSortBase>(options.sort)\n : undefined,\n };\n if (typeof query === 'string') {\n payload.query = query;\n } else if (typeof query === 'object') {\n payload.message_filter_conditions = query;\n } else {\n throw Error(`Invalid type ${typeof query} for query parameter`);\n }\n\n // Make sure we wait for the connect promise if there is a pending one\n await this.wsPromise;\n\n return await this.get<SearchAPIResponse>(this.baseURL + '/search', { payload });\n }\n\n /**\n * setLocalDevice - Set the device info for the current client(device) that will be sent via WS connection automatically\n *\n * @param {BaseDeviceFields} device the device object\n * @param {string} device.id device id\n * @param {string} device.push_provider the push provider\n *\n */\n setLocalDevice(device: BaseDeviceFields) {\n if (\n (this.wsConnection?.isConnecting && this.wsPromise) ||\n ((this.wsConnection?.isHealthy || this.wsFallback?.isHealthy()) &&\n this._hasConnectionID())\n ) {\n throw new Error('you can only set device before opening a websocket connection');\n }\n\n this.options.device = device;\n }\n\n /**\n * addDevice - Adds a push device for a user.\n *\n * @param {string} id the device id\n * @param {PushProvider} push_provider the push provider\n * @param {string} [userID] the user id (defaults to current user)\n * @param {string} [push_provider_name] user provided push provider name for multi bundle support\n *\n */\n async addDevice(\n id: string,\n push_provider: PushProvider,\n userID?: string,\n push_provider_name?: string,\n ) {\n return await this.post<APIResponse>(this.baseURL + '/devices', {\n id,\n push_provider,\n ...(userID != null ? { user_id: userID } : {}),\n ...(push_provider_name != null ? { push_provider_name } : {}),\n });\n }\n\n /**\n * getDevices - Returns the devices associated with a current user\n *\n * @param {string} [userID] User ID. Only works on serverside\n *\n * @return {Device[]} Array of devices\n */\n async getDevices(userID?: string) {\n return await this.get<APIResponse & { devices?: Device[] }>(\n this.baseURL + '/devices',\n userID ? { user_id: userID } : {},\n );\n }\n\n /**\n * getUnreadCount - Returns unread counts for a single user\n *\n * @param {string} [userID] User ID.\n *\n * @return {<GetUnreadCountAPIResponse>}\n */\n async getUnreadCount(userID?: string) {\n return await this.get<GetUnreadCountAPIResponse>(\n this.baseURL + '/unread',\n userID ? { user_id: userID } : {},\n );\n }\n\n /**\n * getUnreadCountBatch - Returns unread counts for multiple users at once. Only works server side.\n *\n * @param {string[]} [userIDs] List of user IDs to fetch unread counts for.\n *\n * @return {<GetUnreadCountBatchAPIResponse>}\n */\n async getUnreadCountBatch(userIDs: string[]) {\n return await this.post<GetUnreadCountBatchAPIResponse>(\n this.baseURL + '/unread_batch',\n { user_ids: userIDs },\n );\n }\n\n /**\n * setPushPreferences - Applies the list of push preferences.\n *\n * @param {PushPreference[]} A list of push preferences.\n *\n * @return {<UpsertPushPreferencesResponse>}\n */\n async setPushPreferences(preferences: PushPreference[]) {\n return await this.post<UpsertPushPreferencesResponse>(\n this.baseURL + '/push_preferences',\n { preferences },\n );\n }\n\n /**\n * removeDevice - Removes the device with the given id. Clientside users can only delete their own devices\n *\n * @param {string} id The device id\n * @param {string} [userID] The user id. Only specify this for serverside requests\n *\n */\n async removeDevice(id: string, userID?: string) {\n return await this.delete<APIResponse>(this.baseURL + '/devices', {\n id,\n ...(userID ? { user_id: userID } : {}),\n });\n }\n\n /**\n * getRateLimits - Returns the rate limits quota and usage for the current app, possibly filter for a specific platform and/or endpoints.\n * Only available server-side.\n *\n * @param {object} [params] The params for the call. If none of the params are set, all limits for all platforms are returned.\n * @returns {Promise<GetRateLimitsResponse>}\n */\n getRateLimits(params?: {\n android?: boolean;\n endpoints?: EndpointName[];\n ios?: boolean;\n serverSide?: boolean;\n web?: boolean;\n }) {\n const { serverSide, web, android, ios, endpoints } = params || {};\n return this.get<GetRateLimitsResponse>(this.baseURL + '/rate_limits', {\n server_side: serverSide,\n web,\n android,\n ios,\n endpoints: endpoints ? endpoints.join(',') : undefined,\n });\n }\n\n /**\n * getHookEvents - Get available events for hooks (webhook, SQS, and SNS)\n *\n * @param {Product[]} [products] Optional array of products to filter events by (e.g., [Product.Chat, Product.Video])\n * @returns {Promise<GetHookEventsResponse>} Response containing available hook events\n */\n async getHookEvents(products?: Product[]) {\n const params = products && products.length > 0 ? { product: products.join(',') } : {};\n return await this.get<GetHookEventsResponse>(this.baseURL + '/hook/events', params);\n }\n\n _addChannelConfig({ cid, config }: ChannelResponse) {\n if (this._cacheEnabled()) {\n this.configs[cid] = config;\n }\n }\n\n /**\n * channel - Returns a new channel with the given type, id and custom data\n *\n * If you want to create a unique conversation between 2 or more users; you can leave out the ID parameter and provide the list of members.\n * Make sure to await channel.create() or channel.watch() before accessing channel functions:\n * ie. channel = client.channel(\"messaging\", {members: [\"tommaso\", \"thierry\"]})\n * await channel.create() to assign an ID to channel\n *\n * @param {string} channelType The channel type\n * @param {string | ChannelData | null} [channelIDOrCustom] The channel ID, you can leave this out if you want to create a conversation channel\n * @param {object} [custom] Custom data to attach to the channel\n *\n * @return {channel} The channel object, initialize it using channel.watch()\n */\n channel(channelType: string, channelID?: string | null, custom?: ChannelData): Channel;\n channel(channelType: string, custom?: ChannelData): Channel;\n channel(\n channelType: string,\n channelIDOrCustom?: string | ChannelData | null,\n custom: ChannelData = {},\n ) {\n if (!this.userID && !this._isUsingServerAuth()) {\n throw Error('Call connectUser or connectAnonymousUser before creating a channel');\n }\n\n if (~channelType.indexOf(':')) {\n throw new Error(\n `Invalid channel group ${channelType}, can't contain the : character`,\n );\n }\n\n // support channel(\"messaging\", {options})\n if (channelIDOrCustom && typeof channelIDOrCustom === 'object') {\n return this.getChannelByMembers(channelType, channelIDOrCustom);\n }\n\n // support channel(\"messaging\", undefined, {options})\n if (!channelIDOrCustom && typeof custom === 'object' && custom.members?.length) {\n return this.getChannelByMembers(channelType, custom);\n }\n\n // support channel(\"messaging\", null, {options})\n // support channel(\"messaging\", undefined, {options})\n // support channel(\"messaging\", \"\", {options})\n if (!channelIDOrCustom) {\n return new Channel(this, channelType, undefined, custom);\n }\n\n return this.getChannelById(channelType, channelIDOrCustom, custom);\n }\n\n /**\n * It's a helper method for `client.channel()` method, used to create unique conversation or\n * channel based on member list instead of id.\n *\n * If the channel already exists in `activeChannels` list, then we simply return it, since that\n * means the same channel was already requested or created.\n *\n * Otherwise we create a new instance of Channel class and return it.\n *\n * @private\n *\n * @param {string} channelType The channel type\n * @param {object} [custom] Custom data to attach to the channel\n *\n * @return {channel} The channel object, initialize it using channel.watch()\n */\n getChannelByMembers = (channelType: string, custom: ChannelData) => {\n // Check if the channel already exists.\n // Only allow 1 channel object per cid\n const memberIds = (custom.members ?? []).map((member: string | NewMemberPayload) =>\n typeof member === 'string' ? member : (member.user_id ?? ''),\n );\n const membersStr = memberIds.sort().join(',');\n const tempCid = generateChannelTempCid(channelType, memberIds);\n\n if (!tempCid) {\n throw Error('Please specify atleast one member when creating unique conversation');\n }\n\n // channel could exist in `activeChannels` list with either one of the following two keys:\n // 1. cid - Which gets set on channel only after calling channel.query or channel.watch or channel.create\n // 2. Sorted membersStr - E.g., \"messaging:amin,vishal\" OR \"messaging:amin,jaap,tom\"\n // This is set when you create a channel, but haven't queried yet. After query,\n // we will replace it with `cid`\n for (const key in this.activeChannels) {\n const channel = this.activeChannels[key];\n if (channel.disconnected) {\n continue;\n }\n\n if (key === tempCid) {\n return channel;\n }\n\n if (key.indexOf(`${channelType}:!members-`) === 0) {\n const membersStrInExistingChannel = Object.keys(channel.state.members)\n .sort()\n .join(',');\n if (membersStrInExistingChannel === membersStr) {\n return channel;\n }\n }\n }\n\n const channel = new Channel(this, channelType, undefined, custom);\n\n // For the time being set the key as membersStr, since we don't know the cid yet.\n // In channel.query, we will replace it with 'cid'.\n if (this._cacheEnabled()) {\n this.activeChannels[tempCid] = channel;\n }\n\n return channel;\n };\n\n /**\n * Its a helper method for `client.channel()` method, used to channel given the id of channel.\n *\n * If the channel already exists in `activeChannels` list, then we simply return it, since that\n * means the same channel was already requested or created.\n *\n * Otherwise we create a new instance of Channel class and return it.\n *\n * @private\n *\n * @param {string} channelType The channel type\n * @param {string} [channelID] The channel ID\n * @param {object} [custom] Custom data to attach to the channel\n *\n * @return {channel} The channel object, initialize it using channel.watch()\n */\n getChannelById = (channelType: string, channelID: string, custom: ChannelData) => {\n if (typeof channelID === 'string' && ~channelID.indexOf(':')) {\n throw Error(`Invalid channel id ${channelID}, can't contain the : character`);\n }\n\n // only allow 1 channel object per cid\n const cid = `${channelType}:${channelID}`;\n if (\n cid in this.activeChannels &&\n this.activeChannels[cid] &&\n !this.activeChannels[cid].disconnected\n ) {\n const channel = this.activeChannels[cid];\n if (Object.keys(custom).length > 0) {\n channel.data = { ...channel.data, ...custom };\n channel._data = { ...channel._data, ...custom };\n }\n return channel;\n }\n const channel = new Channel(this, channelType, channelID, custom);\n if (this._cacheEnabled()) {\n this.activeChannels[channel.cid] = channel;\n }\n\n return channel;\n };\n\n /**\n * partialUpdateUser - Update the given user object\n *\n * @param {PartialUserUpdate} partialUserObject which should contain id and any of \"set\" or \"unset\" params;\n * example: {id: \"user1\", set:{field: value}, unset:[\"field2\"]}\n *\n * @return {Promise<{ users: { [key: string]: UserResponse } }>} list of updated users\n */\n async partialUpdateUser(partialUserObject: PartialUserUpdate) {\n return await this.partialUpdateUsers([partialUserObject]);\n }\n\n /**\n * upsertUsers - Batch upsert the list of users\n *\n * @param {UserResponse[]} users list of users\n *\n * @return {Promise<{ users: { [key: string]: UserResponse } }>}\n */\n async upsertUsers(users: UserResponse[]) {\n const userMap: { [key: string]: UserResponse } = {};\n for (const userObject of users) {\n if (!userObject.id) {\n throw Error('User ID is required when updating a user');\n }\n userMap[userObject.id] = userObject;\n }\n\n return await this.post<\n APIResponse & {\n users: { [key: string]: UserResponse };\n }\n >(this.baseURL + '/users', { users: userMap });\n }\n\n /**\n * @deprecated Please use upsertUsers() function instead.\n *\n * updateUsers - Batch update the list of users\n *\n * @param {UserResponse[]} users list of users\n * @return {Promise<{ users: { [key: string]: UserResponse } }>}\n */\n updateUsers = this.upsertUsers;\n\n /**\n * upsertUser - Update or Create the given user object\n *\n * @param {UserResponse} userObject user object, the only required field is the user id. IE {id: \"myuser\"} is valid\n *\n * @return {Promise<{ users: { [key: string]: UserResponse } }>}\n */\n upsertUser(userObject: UserResponse) {\n return this.upsertUsers([userObject]);\n }\n\n /**\n * @deprecated Please use upsertUser() function instead.\n *\n * updateUser - Update or Create the given user object\n *\n * @param {UserResponse} userObject user object, the only required field is the user id. IE {id: \"myuser\"} is valid\n * @return {Promise<{ users: { [key: string]: UserResponse } }>}\n */\n updateUser = this.upsertUser;\n\n /**\n * partialUpdateUsers - Batch partial update of users\n *\n * @param {PartialUserUpdate[]} users list of partial update requests\n *\n * @return {Promise<{ users: { [key: string]: UserResponse } }>}\n */\n async partialUpdateUsers(users: PartialUserUpdate[]) {\n for (const userObject of users) {\n if (!userObject.id) {\n throw Error('User ID is required when updating a user');\n }\n }\n\n return await this.patch<\n APIResponse & {\n users: { [key: string]: UserResponse };\n }\n >(this.baseURL + '/users', { users });\n }\n\n async deleteUser(\n userID: string,\n params?: {\n delete_conversation_channels?: boolean;\n hard_delete?: boolean;\n mark_messages_deleted?: boolean;\n },\n ) {\n return await this.delete<\n APIResponse & { user: UserResponse } & {\n task_id?: string;\n }\n >(this.baseURL + `/users/${encodeURIComponent(userID)}`, params);\n }\n\n /**\n * restoreUsers - Restore soft deleted users\n *\n * @param {string[]} user_ids which users to restore\n *\n * @return {APIResponse} An API response\n */\n async restoreUsers(user_ids: string[]) {\n return await this.post<APIResponse>(this.baseURL + `/users/restore`, {\n user_ids,\n });\n }\n\n /**\n * reactivateUser - Reactivate one user\n *\n * @param {string} userID which user to reactivate\n * @param {ReactivateUserOptions} [options]\n *\n * @return {UserResponse} Reactivated user\n */\n async reactivateUser(userID: string, options?: ReactivateUserOptions) {\n return await this.post<APIResponse & { user: UserResponse }>(\n this.baseURL + `/users/${encodeURIComponent(userID)}/reactivate`,\n { ...options },\n );\n }\n\n /**\n * reactivateUsers - Reactivate many users asynchronously\n *\n * @param {string[]} user_ids which users to reactivate\n * @param {ReactivateUsersOptions} [options]\n *\n * @return {TaskResponse} A task ID\n */\n async reactivateUsers(user_ids: string[], options?: ReactivateUsersOptions) {\n return await this.post<APIResponse & TaskResponse>(\n this.baseURL + `/users/reactivate`,\n { user_ids, ...options },\n );\n }\n\n /**\n * deactivateUser - Deactivate one user\n *\n * @param {string} userID which user to deactivate\n * @param {DeactivateUsersOptions} [options]\n *\n * @return {UserResponse} Deactivated user\n */\n async deactivateUser(userID: string, options?: DeactivateUsersOptions) {\n return await this.post<APIResponse & { user: UserResponse }>(\n this.baseURL + `/users/${encodeURIComponent(userID)}/deactivate`,\n { ...options },\n );\n }\n\n /**\n * deactivateUsers - Deactivate many users asynchronously\n *\n * @param {string[]} user_ids which users to deactivate\n * @param {DeactivateUsersOptions} [options]\n *\n * @return {TaskResponse} A task ID\n */\n async deactivateUsers(user_ids: string[], options?: DeactivateUsersOptions) {\n return await this.post<APIResponse & TaskResponse>(\n this.baseURL + `/users/deactivate`,\n { user_ids, ...options },\n );\n }\n\n async exportUser(userID: string, options?: Record<string, string>) {\n return await this.get<\n APIResponse & {\n messages: MessageResponse[];\n reactions: ReactionResponse[];\n user: UserResponse;\n }\n >(this.baseURL + `/users/${encodeURIComponent(userID)}/export`, { ...options });\n }\n\n /** banUser - bans a user from all channels\n *\n * @param {string} targetUserID\n * @param {BanUserOptions} [options]\n * @returns {Promise<APIResponse>}\n */\n async banUser(targetUserID: string, options?: BanUserOptions) {\n return await this.post<APIResponse>(this.baseURL + '/moderation/ban', {\n target_user_id: targetUserID,\n ...options,\n });\n }\n\n /** unbanUser - revoke global ban for a user\n *\n * @param {string} targetUserID\n * @param {UnBanUserOptions} [options]\n * @returns {Promise<APIResponse>}\n */\n async unbanUser(targetUserID: string, options?: UnBanUserOptions) {\n return await this.delete<APIResponse>(this.baseURL + '/moderation/ban', {\n target_user_id: targetUserID,\n ...options,\n });\n }\n\n /** shadowBan - shadow bans a user from all channels\n *\n * @param {string} targetUserID\n * @param {BanUserOptions} [options]\n * @returns {Promise<APIResponse>}\n */\n async shadowBan(targetUserID: string, options?: BanUserOptions) {\n return await this.banUser(targetUserID, {\n shadow: true,\n ...options,\n });\n }\n\n /** removeShadowBan - revoke global shadow ban for a user\n *\n * @param {string} targetUserID\n * @param {UnBanUserOptions} [options]\n * @returns {Promise<APIResponse>}\n */\n async removeShadowBan(targetUserID: string, options?: UnBanUserOptions) {\n return await this.unbanUser(targetUserID, {\n shadow: true,\n ...options,\n });\n }\n async blockUser(blockedUserID: string, user_id?: string) {\n return await this.post<BlockUserAPIResponse>(this.baseURL + '/users/block', {\n blocked_user_id: blockedUserID,\n ...(user_id ? { user_id } : {}),\n });\n }\n\n async getBlockedUsers(user_id?: string) {\n return await this.get<GetBlockedUsersAPIResponse>(this.baseURL + '/users/block', {\n ...(user_id ? { user_id } : {}),\n });\n }\n\n async unBlockUser(blockedUserID: string, userID?: string) {\n return await this.post<APIResponse>(this.baseURL + '/users/unblock', {\n blocked_user_id: blockedUserID,\n ...(userID ? { user_id: userID } : {}),\n });\n }\n\n /** getSharedLocations\n *\n * @returns {Promise<ActiveLiveLocationsAPIResponse>} The server response\n *\n */\n async getSharedLocations() {\n return await this.get<ActiveLiveLocationsAPIResponse>(\n this.baseURL + `/users/live_locations`,\n );\n }\n\n /** muteUser - mutes a user\n *\n * @param {string} targetID\n * @param {string} [userID] Only used with serverside auth\n * @param {MuteUserOptions} [options]\n * @returns {Promise<MuteUserResponse>}\n */\n async muteUser(targetID: string, userID?: string, options: MuteUserOptions = {}) {\n return await this.post<MuteUserResponse>(this.baseURL + '/moderation/mute', {\n target_id: targetID,\n ...(userID ? { user_id: userID } : {}),\n ...options,\n });\n }\n\n /** unmuteUser - unmutes a user\n *\n * @param {string} targetID\n * @param {string} [currentUserID] Only used with serverside auth\n * @returns {Promise<APIResponse>}\n */\n async unmuteUser(targetID: string, currentUserID?: string) {\n return await this.post<APIResponse>(this.baseURL + '/moderation/unmute', {\n target_id: targetID,\n ...(currentUserID ? { user_id: currentUserID } : {}),\n });\n }\n\n /** userMuteStatus - check if a user is muted or not, can be used after connectUser() is called\n *\n * @param {string} targetID\n * @returns {boolean}\n */\n userMuteStatus(targetID: string) {\n if (!this.user || !this.wsPromise) {\n throw new Error('Make sure to await connectUser() first.');\n }\n\n for (let i = 0; i < this.mutedUsers.length; i += 1) {\n if (this.mutedUsers[i].target.id === targetID) return true;\n }\n return false;\n }\n\n /**\n * flagMessage - flag a message\n * @param {string} targetMessageID\n * @param {string} [options.user_id] currentUserID, only used with serverside auth\n * @returns {Promise<APIResponse>}\n */\n async flagMessage(\n targetMessageID: string,\n options: { reason?: string; user_id?: string } = {},\n ) {\n return await this.post<FlagMessageResponse>(this.baseURL + '/moderation/flag', {\n target_message_id: targetMessageID,\n ...options,\n });\n }\n\n /**\n * flagUser - flag a user\n * @param {string} targetID\n * @param {string} [options.user_id] currentUserID, only used with serverside auth\n * @returns {Promise<APIResponse>}\n */\n async flagUser(targetID: string, options: { reason?: string; user_id?: string } = {}) {\n return await this.post<FlagUserResponse>(this.baseURL + '/moderation/flag', {\n target_user_id: targetID,\n ...options,\n });\n }\n\n /**\n * unflagMessage - unflag a message\n * @param {string} targetMessageID\n * @param {string} [options.user_id] currentUserID, only used with serverside auth\n * @returns {Promise<APIResponse>}\n */\n async unflagMessage(targetMessageID: string, options: { user_id?: string } = {}) {\n return await this.post<FlagMessageResponse>(this.baseURL + '/moderation/unflag', {\n target_message_id: targetMessageID,\n ...options,\n });\n }\n\n /**\n * unflagUser - unflag a user\n * @param {string} targetID\n * @param {string} [options.user_id] currentUserID, only used with serverside auth\n * @returns {Promise<APIResponse>}\n */\n async unflagUser(targetID: string, options: { user_id?: string } = {}) {\n return await this.post<FlagUserResponse>(this.baseURL + '/moderation/unflag', {\n target_user_id: targetID,\n ...options,\n });\n }\n\n /**\n * _queryFlags - Query flags.\n *\n * Note: Do not use this.\n * It is present for internal usage only.\n * This function can, and will, break and/or be removed at any point in time.\n *\n * @private\n * @param {FlagsFilters} filterConditions MongoDB style filter conditions\n * @param {FlagsPaginationOptions} options Option object, {limit: 10, offset:0}\n *\n * @return {Promise<FlagsResponse>} Flags Response\n */\n async _queryFlags(\n filterConditions: FlagsFilters = {},\n options: FlagsPaginationOptions = {},\n ) {\n // Return a list of flags\n return await this.post<FlagsResponse>(this.baseURL + '/moderation/flags', {\n filter_conditions: filterConditions,\n ...options,\n });\n }\n\n /**\n * _queryFlagReports - Query flag reports.\n *\n * Note: Do not use this.\n * It is present for internal usage only.\n * This function can, and will, break and/or be removed at any point in time.\n *\n * @private\n * @param {FlagReportsFilters} filterConditions MongoDB style filter conditions\n * @param {FlagReportsPaginationOptions} options Option object, {limit: 10, offset:0}\n *\n * @return {Promise<FlagReportsResponse>} Flag Reports Response\n */\n async _queryFlagReports(\n filterConditions: FlagReportsFilters = {},\n options: FlagReportsPaginationOptions = {},\n ) {\n // Return a list of message flags\n return await this.post<FlagReportsResponse>(this.baseURL + '/moderation/reports', {\n filter_conditions: filterConditions,\n ...options,\n });\n }\n\n /**\n * _reviewFlagReport - review flag report\n *\n * Note: Do not use this.\n * It is present for internal usage only.\n * This function can, and will, break and/or be removed at any point in time.\n *\n * @private\n * @param {string} [id] flag report to review\n * @param {string} [reviewResult] flag report review result\n * @param {string} [options.user_id] currentUserID, only used with serverside auth\n * @param {string} [options.review_details] custom information about review result\n * @returns {Promise<ReviewFlagReportResponse>>}\n */\n async _reviewFlagReport(\n id: string,\n reviewResult: string,\n options: ReviewFlagReportOptions = {},\n ) {\n return await this.patch<ReviewFlagReportResponse>(\n this.baseURL + `/moderation/reports/${encodeURIComponent(id)}`,\n {\n review_result: reviewResult,\n ...options,\n },\n );\n }\n\n /**\n * unblockMessage - unblocks message blocked by automod\n *\n *\n * @param {string} targetMessageID\n * @param {string} [options.user_id] currentUserID, only used with serverside auth\n * @returns {Promise<APIResponse>}\n */\n async unblockMessage(targetMessageID: string, options: { user_id?: string } = {}) {\n return await this.post<APIResponse>(this.baseURL + '/moderation/unblock_message', {\n target_message_id: targetMessageID,\n ...options,\n });\n }\n\n // alias for backwards compatibility\n _unblockMessage = this.unblockMessage;\n\n /**\n * @deprecated use markChannelsRead instead\n *\n * markAllRead - marks all channels for this user as read\n * @param {MarkAllReadOptions} [data]\n *\n * @return {Promise<APIResponse>}\n */\n markAllRead = this.markChannelsRead;\n\n /**\n * markChannelsRead - marks channels read -\n * it accepts a map of cid:messageid pairs, if messageid is empty, the whole channel will be marked as read\n *\n * @param {MarkChannelsReadOptions } [data]\n *\n * @return {Promise<APIResponse>}\n */\n async markChannelsRead(data: MarkChannelsReadOptions = {}) {\n await this.post<APIResponse>(this.baseURL + '/channels/read', { ...data });\n }\n\n createCommand(data: CreateCommandOptions) {\n return this.post<CreateCommandResponse>(this.baseURL + '/commands', data);\n }\n\n getCommand(name: string) {\n return this.get<GetCommandResponse>(\n this.baseURL + `/commands/${encodeURIComponent(name)}`,\n );\n }\n\n updateCommand(name: string, data: UpdateCommandOptions) {\n return this.put<UpdateCommandResponse>(\n this.baseURL + `/commands/${encodeURIComponent(name)}`,\n data,\n );\n }\n\n deleteCommand(name: string) {\n return this.delete<DeleteCommandResponse>(\n this.baseURL + `/commands/${encodeURIComponent(name)}`,\n );\n }\n\n listCommands() {\n return this.get<ListCommandsResponse>(this.baseURL + `/commands`);\n }\n\n createChannelType(data: CreateChannelOptions) {\n const channelData = Object.assign({}, { commands: ['all'] }, data);\n return this.post<CreateChannelResponse>(this.baseURL + '/channeltypes', channelData);\n }\n\n getChannelType(channelType: string) {\n return this.get<GetChannelTypeResponse>(\n this.baseURL + `/channeltypes/${encodeURIComponent(channelType)}`,\n );\n }\n\n updateChannelType(channelType: string, data: UpdateChannelTypeRequest) {\n return this.put<UpdateChannelTypeResponse>(\n this.baseURL + `/channeltypes/${encodeURIComponent(channelType)}`,\n data,\n );\n }\n\n deleteChannelType(channelType: string) {\n return this.delete<APIResponse>(\n this.baseURL + `/channeltypes/${encodeURIComponent(channelType)}`,\n );\n }\n\n listChannelTypes() {\n return this.get<ListChannelResponse>(this.baseURL + `/channeltypes`);\n }\n\n /**\n * translateMessage - adds the translation to the message\n *\n * @param {string} messageId\n * @param {string} language\n *\n * @return {MessageResponse} Response that includes the message\n */\n async translateMessage(messageId: string, language: string) {\n return await this.post<APIResponse & MessageResponse>(\n this.baseURL + `/messages/${encodeURIComponent(messageId)}/translate`,\n { language },\n );\n }\n\n /**\n * translate - translates the given text to provided language\n *\n * @param {string} text\n * @param {string} destination_language\n * @param {string} source_language\n *\n * @return {TranslateResponse} Response that includes the message\n */\n async translate(text: string, destination_language: string, source_language: string) {\n return await this.post<APIResponse & TranslateResponse>(this.baseURL + `/translate`, {\n text,\n source_language,\n destination_language,\n });\n }\n\n /**\n * _normalizeExpiration - transforms expiration value into ISO string\n * @param {undefined|null|number|string|Date} timeoutOrExpirationDate expiration date or timeout. Use number type to set timeout in seconds, string or Date to set exact expiration date\n */\n _normalizeExpiration(timeoutOrExpirationDate?: null | number | string | Date) {\n let pinExpires: null | string = null;\n if (typeof timeoutOrExpirationDate === 'number') {\n const now = new Date();\n now.setSeconds(now.getSeconds() + timeoutOrExpirationDate);\n pinExpires = now.toISOString();\n } else if (isString(timeoutOrExpirationDate)) {\n pinExpires = timeoutOrExpirationDate;\n } else if (timeoutOrExpirationDate instanceof Date) {\n pinExpires = timeoutOrExpirationDate.toISOString();\n }\n return pinExpires;\n }\n\n /**\n * _messageId - extracts string message id from either message object or message id\n * @param {string | { id: string }} messageOrMessageId message object or message id\n * @param {string} errorText error message to report in case of message id absence\n */\n _validateAndGetMessageId(\n messageOrMessageId: string | { id: string },\n errorText: string,\n ) {\n let messageId: string;\n if (typeof messageOrMessageId === 'string') {\n messageId = messageOrMessageId;\n } else {\n if (!messageOrMessageId.id) {\n throw Error(errorText);\n }\n messageId = messageOrMessageId.id;\n }\n return messageId;\n }\n\n /**\n * pinMessage - pins the message\n * @param {string | { id: string }} messageOrMessageId message object or message id\n * @param {undefined|null|number|string|Date} timeoutOrExpirationDate expiration date or timeout. Use number type to set timeout in seconds, string or Date to set exact expiration date\n * @param {undefined|string | { id: string }} [pinnedBy] who will appear as a user who pinned a message. Only for server-side use. Provide `undefined` when pinning message client-side\n * @param {undefined|number|string|Date} pinnedAt date when message should be pinned. It affects the order of pinned messages. Use negative number to set relative time in the past, string or Date to set exact date of pin\n */\n pinMessage(\n messageOrMessageId: string | { id: string },\n timeoutOrExpirationDate?: null | number | string | Date,\n pinnedBy?: string | { id: string },\n pinnedAt?: number | string | Date,\n ) {\n const messageId = this._validateAndGetMessageId(\n messageOrMessageId,\n 'Please specify the message id when calling unpinMessage',\n );\n return this.partialUpdateMessage(\n messageId,\n {\n set: {\n pinned: true,\n pin_expires: this._normalizeExpiration(timeoutOrExpirationDate),\n pinned_at: this._normalizeExpiration(pinnedAt),\n },\n } as unknown as PartialMessageUpdate,\n pinnedBy,\n );\n }\n\n /**\n * unpinMessage - unpins the message that was previously pinned\n * @param {string | { id: string }} messageOrMessageId message object or message id\n * @param {string | { id: string }} [userId]\n */\n unpinMessage(\n messageOrMessageId: string | { id: string },\n userId?: string | { id: string },\n ) {\n const messageId = this._validateAndGetMessageId(\n messageOrMessageId,\n 'Please specify the message id when calling unpinMessage',\n );\n return this.partialUpdateMessage(\n messageId,\n {\n set: { pinned: false },\n } as unknown as PartialMessageUpdate,\n userId,\n );\n }\n\n /**\n * updateMessage - Update the given message\n *\n * @param {Omit<MessageResponse, 'mentioned_users'> & { mentioned_users?: string[] }} message object, id needs to be specified\n * @param {string | { id: string }} [partialUserOrUserId]\n * @param {boolean} [options.skip_enrich_url] Do not try to enrich the URLs within message\n *\n * @return {{ message: LocalMessage | MessageResponse }} Response that includes the message\n */\n async updateMessage(\n message: LocalMessage | Partial<MessageResponse>,\n partialUserOrUserId?: string | { id: string },\n options?: UpdateMessageOptions,\n ) {\n if (!message.id) {\n throw Error('Please specify the message.id when calling updateMessage');\n }\n\n // should not include user object\n const payload = toUpdatedMessagePayload(message);\n\n // add user_id (if exists)\n if (typeof partialUserOrUserId === 'string') {\n payload.user_id = partialUserOrUserId;\n } else if (typeof partialUserOrUserId?.id === 'string') {\n payload.user_id = partialUserOrUserId.id;\n }\n\n return await this.post<UpdateMessageAPIResponse>(\n this.baseURL + `/messages/${encodeURIComponent(message.id as string)}`,\n {\n message: payload,\n ...options,\n },\n );\n }\n\n /**\n * partialUpdateMessage - Update the given message id while retaining additional properties\n *\n * @param {string} id the message id\n *\n * @param {PartialUpdateMessage} partialMessageObject which should contain id and any of \"set\" or \"unset\" params;\n * example: {id: \"user1\", set:{text: \"hi\"}, unset:[\"color\"]}\n * @param {string | { id: string }} [userId]\n *\n * @param {boolean} [options.skip_enrich_url] Do not try to enrich the URLs within message\n *\n * @return {{ message: MessageResponse }} Response that includes the updated message\n */\n async partialUpdateMessage(\n id: string,\n partialMessageObject: PartialMessageUpdate,\n partialUserOrUserId?: string | { id: string },\n options?: UpdateMessageOptions,\n ) {\n if (!id) {\n throw Error('Please specify the message.id when calling partialUpdateMessage');\n }\n\n let user: { id: string } | undefined = undefined;\n\n if (typeof partialUserOrUserId === 'string') {\n user = { id: partialUserOrUserId };\n } else if (typeof partialUserOrUserId?.id === 'string') {\n user = { id: partialUserOrUserId.id };\n }\n\n return await this.put<UpdateMessageAPIResponse>(\n this.baseURL + `/messages/${encodeURIComponent(id)}`,\n {\n ...partialMessageObject,\n ...options,\n user,\n },\n );\n }\n\n async deleteMessage(messageID: string, hardDelete?: boolean) {\n try {\n if (this.offlineDb) {\n if (hardDelete) {\n await this.offlineDb.hardDeleteMessage({ id: messageID });\n } else {\n await this.offlineDb.softDeleteMessage({ id: messageID });\n }\n return await this.offlineDb.queueTask<APIResponse & { message: MessageResponse }>(\n {\n task: {\n messageId: messageID,\n payload: [messageID, hardDelete],\n type: 'delete-message',\n },\n },\n );\n }\n } catch (error) {\n this.logger('error', `offlineDb:deleteMessage`, {\n tags: ['channel', 'offlineDb'],\n error,\n });\n }\n\n return this._deleteMessage(messageID, hardDelete);\n }\n\n async _deleteMessage(messageID: string, hardDelete?: boolean) {\n let params = {};\n if (hardDelete) {\n params = { hard: true };\n }\n return await this.delete<APIResponse & { message: MessageResponse }>(\n this.baseURL + `/messages/${encodeURIComponent(messageID)}`,\n params,\n );\n }\n\n /**\n * undeleteMessage - Undelete a message\n *\n * undeletes a message that was previous soft deleted. Hard deleted messages\n * cannot be undeleted. This is only allowed to be called from server-side\n * clients.\n *\n * @param {string} messageID The id of the message to undelete\n * @param {string} userID The id of the user who undeleted the message\n *\n * @return {{ message: MessageResponse }} Response that includes the message\n */\n async undeleteMessage(messageID: string, userID: string) {\n return await this.post<APIResponse & { message: MessageResponse }>(\n this.baseURL + `/messages/${encodeURIComponent(messageID)}/undelete`,\n { undeleted_by: userID },\n );\n }\n\n async getMessage(messageID: string, options?: GetMessageOptions) {\n return await this.get<GetMessageAPIResponse>(\n this.baseURL + `/messages/${encodeURIComponent(messageID)}`,\n {\n ...options,\n },\n );\n }\n\n /**\n * queryThreads - returns the list of threads of current user.\n *\n * @param {QueryThreadsOptions} options Options object for pagination and limiting the participants and replies.\n * @param {number} options.limit Limits the number of threads to be returned.\n * @param {boolean} options.watch Subscribes the user to the channels of the threads.\n * @param {number} options.participant_limit Limits the number of participants returned per threads.\n * @param {number} options.reply_limit Limits the number of replies returned per threads.\n * @param {ThreadFilters} options.filter MongoDB style filters for threads\n * @param {ThreadSort} options.sort MongoDB style sort for threads\n *\n * @returns {{ threads: Thread[], next: string }} Returns the list of threads and the next cursor.\n */\n async queryThreads(options: QueryThreadsOptions = {}) {\n const optionsWithDefaults = {\n limit: 10,\n participant_limit: 10,\n reply_limit: 3,\n watch: true,\n ...options,\n };\n\n const requestBody: Record<string, unknown> = {\n ...optionsWithDefaults,\n };\n\n if (\n optionsWithDefaults.filter &&\n Object.keys(optionsWithDefaults.filter).length > 0\n ) {\n requestBody.filter = optionsWithDefaults.filter;\n }\n\n if (\n optionsWithDefaults.sort &&\n (Array.isArray(optionsWithDefaults.sort)\n ? optionsWithDefaults.sort.length > 0\n : Object.keys(optionsWithDefaults.sort).length > 0)\n ) {\n requestBody.sort = normalizeQuerySort(optionsWithDefaults.sort);\n }\n\n const response = await this.post<QueryThreadsAPIResponse>(\n `${this.baseURL}/threads`,\n requestBody,\n );\n\n return {\n threads: response.threads.map(\n (thread) => new Thread({ client: this, threadData: thread }),\n ),\n next: response.next,\n };\n }\n\n /**\n * getThread - returns the thread of a message by its id.\n *\n * @param {string} messageId The message id\n * @param {GetThreadOptions} options Options object for pagination and limiting the participants and replies.\n * @param {boolean} options.watch Subscribes the user to the channel of the thread.\n * @param {number} options.participant_limit Limits the number of participants returned per threads.\n * @param {number} options.reply_limit Limits the number of replies returned per threads.\n *\n * @returns {Thread} Returns the thread.\n */\n async getThread(messageId: string, options: GetThreadOptions = {}) {\n if (!messageId) {\n throw new Error('Please specify the messageId when calling getThread');\n }\n\n const optionsWithDefaults = {\n participant_limit: 100,\n reply_limit: 3,\n watch: true,\n ...options,\n };\n\n const response = await this.get<GetThreadAPIResponse>(\n `${this.baseURL}/threads/${encodeURIComponent(messageId)}`,\n optionsWithDefaults,\n );\n\n return new Thread({ client: this, threadData: response.thread });\n }\n\n /**\n * partialUpdateThread - updates the given thread\n *\n * @param {string} messageId The id of the thread message which needs to be updated.\n * @param {PartialThreadUpdate} partialThreadObject should contain \"set\" or \"unset\" params for any of the thread's non-reserved fields.\n *\n * @returns {GetThreadAPIResponse} Returns the updated thread.\n */\n async partialUpdateThread(messageId: string, partialThreadObject: PartialThreadUpdate) {\n if (!messageId) {\n throw Error('Please specify the message id when calling partialUpdateThread');\n }\n\n // check for reserved fields from ThreadResponse type within partialThreadObject's set and unset.\n // Throw error if any of the reserved field is found.\n const reservedThreadFields = [\n 'created_at',\n 'id',\n 'last_message_at',\n 'type',\n 'updated_at',\n 'user',\n 'reply_count',\n 'participants',\n 'channel',\n 'custom',\n ];\n\n for (const key in { ...partialThreadObject.set, ...partialThreadObject.unset }) {\n if (reservedThreadFields.includes(key)) {\n throw Error(\n `You cannot set ${key} field on Thread object. ${key} is reserved for server-side use. Please omit ${key} from your set object.`,\n );\n }\n }\n\n return await this.patch<GetThreadAPIResponse>(\n `${this.baseURL}/threads/${encodeURIComponent(messageId)}`,\n partialThreadObject,\n );\n }\n\n getUserAgent() {\n if (this.userAgent) {\n return this.userAgent;\n }\n\n const version = process.env.PKG_VERSION;\n const clientBundle = process.env.CLIENT_BUNDLE;\n\n let userAgentString = '';\n if (this.sdkIdentifier) {\n userAgentString = `stream-chat-${this.sdkIdentifier.name}-v${this.sdkIdentifier.version}-llc-v${version}`;\n } else {\n userAgentString = `stream-chat-js-v${version}-${this.node ? 'node' : 'browser'}`;\n }\n\n const { os, model } = this.deviceIdentifier ?? {};\n\n return (\n [\n // reports the device OS, if provided\n ['os', os],\n // reports the device model, if provided\n ['device_model', model],\n // reports which bundle is being picked from the exports\n ['client_bundle', clientBundle],\n ] as const\n ).reduce(\n (withArguments, [key, value]) =>\n value && value.length > 0\n ? withArguments.concat(`|${key}=${value}`)\n : withArguments,\n userAgentString,\n );\n }\n\n /**\n * @deprecated use sdkIdentifier instead\n * @param userAgent\n */\n setUserAgent(userAgent: string) {\n this.userAgent = userAgent;\n }\n\n /**\n * _isUsingServerAuth - Returns true if we're using server side auth\n */\n _isUsingServerAuth = () => !!this.secret;\n\n _cacheEnabled = () => !this._isUsingServerAuth() || !this.options.disableCache;\n\n _enrichAxiosOptions(\n options: AxiosRequestConfig & { config?: AxiosRequestConfig } = {\n params: {},\n headers: {},\n config: {},\n },\n ): AxiosRequestConfig {\n const token = this._getToken();\n const authorization = token ? { Authorization: token } : undefined;\n let signal: AbortSignal | null = null;\n if (this.nextRequestAbortController !== null) {\n signal = this.nextRequestAbortController.signal;\n this.nextRequestAbortController = null;\n }\n\n if (!options.headers?.['x-client-request-id']) {\n options.headers = {\n ...options.headers,\n 'x-client-request-id': randomId(),\n };\n }\n\n const {\n params: axiosRequestConfigParams,\n headers: axiosRequestConfigHeaders,\n ...axiosRequestConfigRest\n } = this.options.axiosRequestConfig || {};\n\n return {\n params: {\n user_id: this.userID,\n connection_id: this._getConnectionID(),\n api_key: this.key,\n ...options.params,\n ...(axiosRequestConfigParams || {}),\n },\n headers: {\n ...authorization,\n 'stream-auth-type': this.getAuthType(),\n 'X-Stream-Client': this.getUserAgent(),\n ...options.headers,\n ...(axiosRequestConfigHeaders || {}),\n },\n ...(signal ? { signal } : {}),\n ...options.config,\n ...(axiosRequestConfigRest || {}),\n };\n }\n\n _getToken() {\n if (!this.tokenManager || this.anonymous) return null;\n\n return this.tokenManager.getToken();\n }\n\n _startCleaning() {\n // eslint-disable-next-line @typescript-eslint/no-this-alias\n const that = this;\n if (this.cleaningIntervalRef != null) {\n return;\n }\n this.cleaningIntervalRef = setInterval(() => {\n // call clean on the channel, used for calling the stop.typing event etc.\n for (const channel of Object.values(that.activeChannels)) {\n channel.clean();\n }\n }, 500);\n }\n\n /**\n * encode ws url payload\n * @private\n * @returns json string\n */\n _buildWSPayload = (client_request_id?: string) =>\n JSON.stringify({\n user_id: this.userID,\n user_details: this._user,\n device: this.options.device,\n client_request_id,\n });\n\n /**\n * checks signature of a request\n * @param {string | Buffer} rawBody\n * @param {string} signature from HTTP header\n * @returns {boolean}\n */\n verifyWebhook(requestBody: string | Buffer, xSignature: string) {\n return !!this.secret && CheckSignature(requestBody, this.secret, xSignature);\n }\n\n /** getPermission - gets the definition for a permission\n *\n * @param {string} name\n * @returns {Promise<PermissionAPIResponse>}\n */\n getPermission(name: string) {\n return this.get<PermissionAPIResponse>(\n `${this.baseURL}/permissions/${encodeURIComponent(name)}`,\n );\n }\n\n /** createPermission - creates a custom permission\n *\n * @param {CustomPermissionOptions} permissionData the permission data\n * @returns {Promise<APIResponse>}\n */\n createPermission(permissionData: CustomPermissionOptions) {\n return this.post<APIResponse>(`${this.baseURL}/permissions`, {\n ...permissionData,\n });\n }\n\n /** updatePermission - updates an existing custom permission\n *\n * @param {string} id\n * @param {Omit<CustomPermissionOptions, 'id'>} permissionData the permission data\n * @returns {Promise<APIResponse>}\n */\n updatePermission(id: string, permissionData: Omit<CustomPermissionOptions, 'id'>) {\n return this.put<APIResponse>(\n `${this.baseURL}/permissions/${encodeURIComponent(id)}`,\n {\n ...permissionData,\n },\n );\n }\n\n /** deletePermission - deletes a custom permission\n *\n * @param {string} name\n * @returns {Promise<APIResponse>}\n */\n deletePermission(name: string) {\n return this.delete<APIResponse>(\n `${this.baseURL}/permissions/${encodeURIComponent(name)}`,\n );\n }\n\n /** listPermissions - returns the list of all permissions for this application\n *\n * @returns {Promise<APIResponse>}\n */\n listPermissions() {\n return this.get<PermissionsAPIResponse>(`${this.baseURL}/permissions`);\n }\n\n /** createRole - creates a custom role\n *\n * @param {string} name the new role name\n * @returns {Promise<APIResponse>}\n */\n createRole(name: string) {\n return this.post<APIResponse>(`${this.baseURL}/roles`, { name });\n }\n\n /** listRoles - returns the list of all roles for this application\n *\n * @returns {Promise<APIResponse>}\n */\n listRoles() {\n return this.get<APIResponse>(`${this.baseURL}/roles`);\n }\n\n /** deleteRole - deletes a custom role\n *\n * @param {string} name the role name\n * @returns {Promise<APIResponse>}\n */\n deleteRole(name: string) {\n return this.delete<APIResponse>(`${this.baseURL}/roles/${encodeURIComponent(name)}`);\n }\n\n /** sync - returns all events that happened for a list of channels since last sync\n * @param {string[]} channel_cids list of channel CIDs\n * @param {string} last_sync_at last time the user was online and in sync. RFC3339 ie. \"2020-05-06T15:05:01.207Z\"\n * @param {SyncOptions} options See JSDoc in the type fields for more info\n *\n * @returns {Promise<SyncResponse>}\n */\n sync(channel_cids: string[], last_sync_at: string, options: SyncOptions = {}) {\n return this.post<SyncResponse>(`${this.baseURL}/sync`, {\n channel_cids,\n last_sync_at,\n ...options,\n });\n }\n\n /**\n * sendUserCustomEvent - Send a custom event to a user\n *\n * @param {string} targetUserID target user id\n * @param {UserCustomEvent} event for example {type: 'friendship-request'}\n *\n * @return {Promise<APIResponse>} The Server Response\n */\n async sendUserCustomEvent(targetUserID: string, event: UserCustomEvent) {\n return await this.post<APIResponse>(\n `${this.baseURL}/users/${encodeURIComponent(targetUserID)}/event`,\n {\n event,\n },\n );\n }\n\n /**\n * Creates a new block list\n *\n * @param {BlockList} blockList - The block list to create\n * @param {string} blockList.name - The name of the block list\n * @param {string[]} blockList.words - List of words to block\n * @param {string} [blockList.team] - Team ID the block list belongs to\n *\n * @returns {Promise<APIResponse>} The server response\n */\n createBlockList(blockList: BlockList) {\n return this.post<APIResponse>(`${this.baseURL}/blocklists`, blockList);\n }\n\n /**\n * Lists all block lists\n *\n * @param {Object} [data] - Query parameters\n * @param {string} [data.team] - Team ID to filter block lists by\n *\n * @returns {Promise<APIResponse & {blocklists: BlockListResponse[]}>} Response containing array of block lists\n */\n listBlockLists(data?: { team?: string }) {\n return this.get<APIResponse & { blocklists: BlockListResponse[] }>(\n `${this.baseURL}/blocklists`,\n data,\n );\n }\n\n /**\n * Gets a specific block list\n *\n * @param {string} name - The name of the block list to retrieve\n * @param {Object} [data] - Query parameters\n * @param {string} [data.team] - Team ID that blocklist belongs to\n *\n * @returns {Promise<APIResponse & {blocklist: BlockListResponse}>} Response containing the block list\n */\n getBlockList(name: string, data?: { team?: string }) {\n return this.get<APIResponse & { blocklist: BlockListResponse }>(\n `${this.baseURL}/blocklists/${encodeURIComponent(name)}`,\n data,\n );\n }\n\n /**\n * Updates an existing block list\n *\n * @param {string} name - The name of the block list to update\n * @param {Object} data - The update data\n * @param {string[]} data.words - New list of words to block\n * @param {string} [data.team] - Team ID that blocklist belongs to\n *\n * @returns {Promise<APIResponse>} The server response\n */\n updateBlockList(name: string, data: { words: string[]; team?: string }) {\n return this.put<APIResponse>(\n `${this.baseURL}/blocklists/${encodeURIComponent(name)}`,\n data,\n );\n }\n\n /**\n * Deletes a block list\n *\n * @param {string} name - The name of the block list to delete\n * @param {Object} [data] - Query parameters\n * @param {string} [data.team] - Team ID that blocklist belongs to\n *\n * @returns {Promise<APIResponse>} The server response\n */\n deleteBlockList(name: string, data?: { team?: string }) {\n return this.delete<APIResponse>(\n `${this.baseURL}/blocklists/${encodeURIComponent(name)}`,\n data,\n );\n }\n\n exportChannels(\n request: Array<ExportChannelRequest>,\n options: ExportChannelOptions = {},\n ) {\n const payload = { channels: request, ...options };\n return this.post<APIResponse & ExportChannelResponse>(\n `${this.baseURL}/export_channels`,\n payload,\n );\n }\n\n exportUsers(request: ExportUsersRequest) {\n return this.post<APIResponse & ExportUsersResponse>(\n `${this.baseURL}/export/users`,\n request,\n );\n }\n\n exportChannel(request: ExportChannelRequest, options?: ExportChannelOptions) {\n return this.exportChannels([request], options);\n }\n\n getExportChannelStatus(id: string) {\n return this.get<APIResponse & ExportChannelStatusResponse>(\n `${this.baseURL}/export_channels/${encodeURIComponent(id)}`,\n );\n }\n\n campaign(idOrData: string | CampaignData, data?: CampaignData) {\n if (idOrData && typeof idOrData === 'object') {\n return new Campaign(this, null, idOrData);\n }\n\n return new Campaign(this, idOrData, data);\n }\n\n segment(type: SegmentType, idOrData: string | SegmentData, data?: SegmentData) {\n if (typeof idOrData === 'string') {\n return new Segment(this, type, idOrData, data);\n }\n\n return new Segment(this, type, null, idOrData);\n }\n\n validateServerSideAuth() {\n if (!this.secret) {\n throw new Error(\n 'Campaigns is a server-side only feature. Please initialize the client with a secret to use this feature.',\n );\n }\n }\n\n /**\n * createSegment - Creates a segment\n *\n * @private\n * @param {SegmentType} type Segment type\n * @param {string} id Segment ID\n * @param {string} name Segment name\n * @param {SegmentData} params Segment data\n *\n * @return {{segment: SegmentResponse} & APIResponse} The created Segment\n */\n createSegment(type: SegmentType, id: string | null, data?: SegmentData) {\n this.validateServerSideAuth();\n const body = {\n id,\n type,\n ...data,\n };\n return this.post<{ segment: SegmentResponse }>(this.baseURL + `/segments`, body);\n }\n\n /**\n * createUserSegment - Creates a user segment\n *\n * @param {string} id Segment ID\n * @param {string} name Segment name\n * @param {SegmentData} data Segment data\n *\n * @return {Segment} The created Segment\n */\n createUserSegment(id: string | null, data?: SegmentData) {\n this.validateServerSideAuth();\n return this.createSegment('user', id, data);\n }\n\n /**\n * createChannelSegment - Creates a channel segment\n *\n * @param {string} id Segment ID\n * @param {string} name Segment name\n * @param {SegmentData} data Segment data\n *\n * @return {Segment} The created Segment\n */\n createChannelSegment(id: string | null, data?: SegmentData) {\n this.validateServerSideAuth();\n return this.createSegment('channel', id, data);\n }\n\n getSegment(id: string) {\n this.validateServerSideAuth();\n return this.get<{ segment: SegmentResponse } & APIResponse>(\n this.baseURL + `/segments/${encodeURIComponent(id)}`,\n );\n }\n\n /**\n * updateSegment - Update a segment\n *\n * @param {string} id Segment ID\n * @param {Partial<UpdateSegmentData>} data Data to update\n *\n * @return {Segment} Updated Segment\n */\n updateSegment(id: string, data: Partial<UpdateSegmentData>) {\n this.validateServerSideAuth();\n return this.put<{ segment: SegmentResponse }>(\n this.baseURL + `/segments/${encodeURIComponent(id)}`,\n data,\n );\n }\n\n /**\n * addSegmentTargets - Add targets to a segment\n *\n * @param {string} id Segment ID\n * @param {string[]} targets Targets to add to the segment\n *\n * @return {APIResponse} API response\n */\n addSegmentTargets(id: string, targets: string[]) {\n this.validateServerSideAuth();\n const body = { target_ids: targets };\n return this.post<APIResponse>(\n this.baseURL + `/segments/${encodeURIComponent(id)}/addtargets`,\n body,\n );\n }\n\n querySegmentTargets(\n id: string,\n filter: QuerySegmentTargetsFilter | null = {},\n sort: SortParam[] | null | [] = [],\n options = {},\n ) {\n this.validateServerSideAuth();\n return this.post<{ targets: SegmentTargetsResponse[]; next?: string } & APIResponse>(\n this.baseURL + `/segments/${encodeURIComponent(id)}/targets/query`,\n {\n filter: filter || {},\n sort: sort || [],\n ...options,\n },\n );\n }\n /**\n * removeSegmentTargets - Remove targets from a segment\n *\n * @param {string} id Segment ID\n * @param {string[]} targets Targets to add to the segment\n *\n * @return {APIResponse} API response\n */\n removeSegmentTargets(id: string, targets: string[]) {\n this.validateServerSideAuth();\n const body = { target_ids: targets };\n return this.post<APIResponse>(\n this.baseURL + `/segments/${encodeURIComponent(id)}/deletetargets`,\n body,\n );\n }\n\n /**\n * querySegments - Query Segments\n *\n * @param {filter} filter MongoDB style filter conditions\n * @param {QuerySegmentsOptions} options Options for sorting/paginating the results\n *\n * @return {Segment[]} Segments\n */\n querySegments(filter: {}, sort?: SortParam[], options: QuerySegmentsOptions = {}) {\n this.validateServerSideAuth();\n return this.post<\n {\n segments: SegmentResponse[];\n next?: string;\n prev?: string;\n } & APIResponse\n >(this.baseURL + `/segments/query`, {\n filter,\n sort,\n ...options,\n });\n }\n\n /**\n * deleteSegment - Delete a Campaign Segment\n *\n * @param {string} id Segment ID\n *\n * @return {Promise<APIResponse>} The Server Response\n */\n deleteSegment(id: string) {\n this.validateServerSideAuth();\n return this.delete<APIResponse>(this.baseURL + `/segments/${encodeURIComponent(id)}`);\n }\n\n /**\n * segmentTargetExists - Check if a target exists in a segment\n *\n * @param {string} segmentId Segment ID\n * @param {string} targetId Target ID\n *\n * @return {Promise<APIResponse>} The Server Response\n */\n segmentTargetExists(segmentId: string, targetId: string) {\n this.validateServerSideAuth();\n return this.get<APIResponse>(\n this.baseURL +\n `/segments/${encodeURIComponent(segmentId)}/target/${encodeURIComponent(targetId)}`,\n );\n }\n\n /**\n * createCampaign - Creates a Campaign\n *\n * @param {CampaignData} params Campaign data\n *\n * @return {Campaign} The Created Campaign\n */\n createCampaign(params: CampaignData) {\n this.validateServerSideAuth();\n return this.post<\n {\n campaign: CampaignResponse;\n users: {\n next?: string;\n prev?: string;\n };\n } & APIResponse\n >(this.baseURL + `/campaigns`, { ...params });\n }\n\n getCampaign(id: string, options?: GetCampaignOptions) {\n this.validateServerSideAuth();\n return this.get<\n {\n campaign: CampaignResponse;\n users: {\n next?: string;\n prev?: string;\n };\n } & APIResponse\n >(this.baseURL + `/campaigns/${encodeURIComponent(id)}`, { ...options?.users });\n }\n\n startCampaign(id: string, options?: { scheduledFor?: string; stopAt?: string }) {\n this.validateServerSideAuth();\n return this.post<\n {\n campaign: CampaignResponse;\n users: {\n next?: string;\n prev?: string;\n };\n } & APIResponse\n >(this.baseURL + `/campaigns/${encodeURIComponent(id)}/start`, {\n scheduled_for: options?.scheduledFor,\n stop_at: options?.stopAt,\n });\n }\n\n /**\n * queryCampaigns - Query Campaigns\n *\n *\n * @return {Campaign[]} Campaigns\n */\n async queryCampaigns(\n filter: CampaignFilters,\n sort?: CampaignSort,\n options?: CampaignQueryOptions,\n ) {\n this.validateServerSideAuth();\n return await this.post<\n {\n campaigns: CampaignResponse[];\n next?: string;\n prev?: string;\n } & APIResponse\n >(this.baseURL + `/campaigns/query`, {\n filter,\n sort,\n ...(options || {}),\n });\n }\n\n /**\n * updateCampaign - Update a Campaign\n *\n * @param {string} id Campaign ID\n * @param {Partial<CampaignData>} params Campaign data\n *\n * @return {Campaign} Updated Campaign\n */\n updateCampaign(id: string, params: Partial<CampaignData>) {\n this.validateServerSideAuth();\n return this.put<{\n campaign: CampaignResponse;\n users: {\n next?: string;\n prev?: string;\n };\n }>(this.baseURL + `/campaigns/${encodeURIComponent(id)}`, params);\n }\n\n /**\n * deleteCampaign - Delete a Campaign\n *\n * @param {string} id Campaign ID\n *\n * @return {Promise<APIResponse>} The Server Response\n */\n deleteCampaign(id: string) {\n this.validateServerSideAuth();\n return this.delete<APIResponse>(\n this.baseURL + `/campaigns/${encodeURIComponent(id)}`,\n );\n }\n\n /**\n * stopCampaign - Stop a Campaign\n *\n * @param {string} id Campaign ID\n *\n * @return {Campaign} Stopped Campaign\n */\n stopCampaign(id: string) {\n this.validateServerSideAuth();\n return this.post<{ campaign: CampaignResponse }>(\n this.baseURL + `/campaigns/${encodeURIComponent(id)}/stop`,\n );\n }\n\n /**\n * enrichURL - Get OpenGraph data of the given link\n *\n * @param {string} url link\n * @return {OGAttachment} OG Attachment\n */\n enrichURL(url: string) {\n return this.get<APIResponse & OGAttachment>(this.baseURL + `/og`, { url });\n }\n\n /**\n * getTask - Gets status of a long running task\n *\n * @param {string} id Task ID\n *\n * @return {TaskStatus} The task status\n */\n getTask(id: string) {\n return this.get<APIResponse & TaskStatus>(\n `${this.baseURL}/tasks/${encodeURIComponent(id)}`,\n );\n }\n\n /**\n * deleteChannels - Deletes a list of channel\n *\n * @param {string[]} cids Channel CIDs\n * @param {boolean} [options.hard_delete] Defines if the channel is hard deleted or not\n *\n * @return {DeleteChannelsResponse} Result of the soft deletion, if server-side, it holds the task ID as well\n */\n async deleteChannels(cids: string[], options: { hard_delete?: boolean } = {}) {\n return await this.post<APIResponse & DeleteChannelsResponse>(\n this.baseURL + `/channels/delete`,\n {\n cids,\n ...options,\n },\n );\n }\n\n /**\n * deleteUsers - Batch Delete Users\n *\n * @param {string[]} user_ids which users to delete\n * @param {DeleteUserOptions} options Configuration how to delete users\n *\n * @return {TaskResponse} A task ID\n */\n async deleteUsers(user_ids: string[], options: DeleteUserOptions = {}) {\n if (\n typeof options.user !== 'undefined' &&\n !['soft', 'hard', 'pruning'].includes(options.user)\n ) {\n throw new Error(\n 'Invalid delete user options. user must be one of [soft hard pruning]',\n );\n }\n if (\n typeof options.conversations !== 'undefined' &&\n !['soft', 'hard'].includes(options.conversations)\n ) {\n throw new Error(\n 'Invalid delete user options. conversations must be one of [soft hard]',\n );\n }\n if (\n typeof options.messages !== 'undefined' &&\n !['soft', 'hard', 'pruning'].includes(options.messages)\n ) {\n throw new Error(\n 'Invalid delete user options. messages must be one of [soft hard pruning]',\n );\n }\n return await this.post<APIResponse & TaskResponse>(this.baseURL + `/users/delete`, {\n user_ids,\n ...options,\n });\n }\n\n /**\n * _createImportURL - Create an Import upload url.\n *\n * Note: Do not use this.\n * It is present for internal usage only.\n * This function can, and will, break and/or be removed at any point in time.\n *\n * @private\n * @param {string} filename filename of uploaded data\n * @return {APIResponse & CreateImportResponse} An ImportTask\n */\n async _createImportURL(filename: string) {\n return await this.post<APIResponse & CreateImportURLResponse>(\n this.baseURL + `/import_urls`,\n {\n filename,\n },\n );\n }\n\n /**\n * _createImport - Create an Import Task.\n *\n * Note: Do not use this.\n * It is present for internal usage only.\n * This function can, and will, break and/or be removed at any point in time.\n *\n * @private\n * @param {string} path path of uploaded data\n * @param {CreateImportOptions} options import options\n * @return {APIResponse & CreateImportResponse} An ImportTask\n */\n async _createImport(path: string, options: CreateImportOptions = { mode: 'upsert' }) {\n return await this.post<APIResponse & CreateImportResponse>(\n this.baseURL + `/imports`,\n {\n path,\n ...options,\n },\n );\n }\n\n /**\n * _getImport - Get an Import Task.\n *\n * Note: Do not use this.\n * It is present for internal usage only.\n * This function can, and will, break and/or be removed at any point in time.\n *\n * @private\n * @param {string} id id of Import Task\n *\n * @return {APIResponse & GetImportResponse} An ImportTask\n */\n async _getImport(id: string) {\n return await this.get<APIResponse & GetImportResponse>(\n this.baseURL + `/imports/${encodeURIComponent(id)}`,\n );\n }\n\n /**\n * _listImports - Lists Import Tasks.\n *\n * Note: Do not use this.\n * It is present for internal usage only.\n * This function can, and will, break and/or be removed at any point in time.\n *\n * @private\n * @param {ListImportsPaginationOptions} options pagination options\n *\n * @return {APIResponse & ListImportsResponse} An ImportTask\n */\n async _listImports(options: ListImportsPaginationOptions) {\n return await this.get<APIResponse & ListImportsResponse>(\n this.baseURL + `/imports`,\n options,\n );\n }\n\n /**\n * upsertPushProvider - Create or Update a push provider\n *\n * Note: Works only for v2 push version is enabled on app settings.\n *\n * @param {PushProviderConfig} configuration of the provider you want to create or update\n *\n * @return {APIResponse & PushProviderUpsertResponse} A push provider\n */\n async upsertPushProvider(pushProvider: PushProviderConfig) {\n return await this.post<APIResponse & PushProviderUpsertResponse>(\n this.baseURL + `/push_providers`,\n {\n push_provider: pushProvider,\n },\n );\n }\n\n /**\n * deletePushProvider - Delete a push provider\n *\n * Note: Works only for v2 push version is enabled on app settings.\n *\n * @param {PushProviderID} type and foreign id of the push provider to be deleted\n *\n * @return {APIResponse} An API response\n */\n async deletePushProvider({ type, name }: PushProviderID) {\n return await this.delete<APIResponse>(\n this.baseURL +\n `/push_providers/${encodeURIComponent(type)}/${encodeURIComponent(name)}`,\n );\n }\n\n /**\n * listPushProviders - Get all push providers in the app\n *\n * Note: Works only for v2 push version is enabled on app settings.\n *\n * @return {APIResponse & PushProviderListResponse} A push provider\n */\n async listPushProviders() {\n return await this.get<APIResponse & PushProviderListResponse>(\n this.baseURL + `/push_providers`,\n );\n }\n\n /**\n * creates an abort controller that will be used by the next HTTP Request.\n */\n createAbortControllerForNextRequest() {\n return (this.nextRequestAbortController = new AbortController());\n }\n\n /**\n * commits a pending message, making it visible in the channel and for other users\n * @param id the message id\n *\n * @return {APIResponse & MessageResponse} The message\n */\n async commitMessage(id: string) {\n return await this.post<APIResponse & MessageResponse>(\n this.baseURL + `/messages/${encodeURIComponent(id)}/commit`,\n );\n }\n\n /**\n * Creates a poll\n * @param poll PollData The poll that will be created\n * @param userId string The user id (only serverside)\n * @returns {APIResponse & CreatePollAPIResponse} The poll\n */\n async createPoll(poll: CreatePollData, userId?: string) {\n return await this.post<APIResponse & CreatePollAPIResponse>(this.baseURL + `/polls`, {\n ...poll,\n ...(userId ? { user_id: userId } : {}),\n });\n }\n\n /**\n * Retrieves a poll\n * @param id string The poll id\n * @param userId string The user id (only serverside)\n * @returns {APIResponse & GetPollAPIResponse} The poll\n */\n async getPoll(id: string, userId?: string): Promise<APIResponse & GetPollAPIResponse> {\n return await this.get<APIResponse & GetPollAPIResponse>(\n this.baseURL + `/polls/${encodeURIComponent(id)}`,\n userId ? { user_id: userId } : {},\n );\n }\n\n /**\n * Updates a poll\n * @param poll PollData The poll that will be updated\n * @param userId string The user id (only serverside)\n * @returns {APIResponse & PollResponse} The poll\n */\n async updatePoll(poll: PollData, userId?: string) {\n return await this.put<APIResponse & UpdatePollAPIResponse>(this.baseURL + `/polls`, {\n ...poll,\n ...(userId ? { user_id: userId } : {}),\n });\n }\n\n /**\n * Partially updates a poll\n * @param id string The poll id\n * @param {PartialPollUpdate} partialPollObject which should contain id and any of \"set\" or \"unset\" params;\n * @param userId string The user id (only serverside)\n * example: {id: \"44f26af5-f2be-4fa7-9dac-71cf893781de\", set:{field: value}, unset:[\"field2\"]}\n * @returns {APIResponse & UpdatePollAPIResponse} The poll\n */\n async partialUpdatePoll(\n id: string,\n partialPollObject: PartialPollUpdate,\n userId?: string,\n ): Promise<APIResponse & UpdatePollAPIResponse> {\n return await this.patch<APIResponse & UpdatePollAPIResponse>(\n this.baseURL + `/polls/${encodeURIComponent(id)}`,\n {\n ...partialPollObject,\n ...(userId ? { user_id: userId } : {}),\n },\n );\n }\n\n /**\n * Delete a poll\n * @param id string The poll id\n * @param userId string The user id (only serverside)\n * @returns\n */\n async deletePoll(id: string, userId?: string): Promise<APIResponse> {\n return await this.delete<APIResponse>(\n this.baseURL + `/polls/${encodeURIComponent(id)}`,\n {\n ...(userId ? { user_id: userId } : {}),\n },\n );\n }\n\n /**\n * Close a poll\n * @param id string The poll id\n * @param userId string The user id (only serverside)\n * @returns {APIResponse & UpdatePollAPIResponse} The poll\n */\n closePoll(id: string, userId?: string): Promise<APIResponse & UpdatePollAPIResponse> {\n return this.partialUpdatePoll(\n id,\n {\n set: {\n is_closed: true,\n } as PartialPollUpdate['set'],\n },\n userId,\n );\n }\n\n /**\n * Creates a poll option\n * @param pollId string The poll id\n * @param option PollOptionData The poll option that will be created\n * @param userId string The user id (only serverside)\n * @returns {APIResponse & PollOptionResponse} The poll option\n */\n async createPollOption(pollId: string, option: PollOptionData, userId?: string) {\n return await this.post<APIResponse & CreatePollOptionAPIResponse>(\n this.baseURL + `/polls/${encodeURIComponent(pollId)}/options`,\n {\n ...option,\n ...(userId ? { user_id: userId } : {}),\n },\n );\n }\n\n /**\n * Retrieves a poll option\n * @param pollId string The poll id\n * @param optionId string The poll option id\n * @param userId string The user id (only serverside)\n * @returns {APIResponse & PollOptionResponse} The poll option\n */\n async getPollOption(pollId: string, optionId: string, userId?: string) {\n return await this.get<APIResponse & GetPollOptionAPIResponse>(\n this.baseURL +\n `/polls/${encodeURIComponent(pollId)}/options/${encodeURIComponent(optionId)}`,\n userId ? { user_id: userId } : {},\n );\n }\n\n /**\n * Updates a poll option\n * @param pollId string The poll id\n * @param option PollOptionData The poll option that will be updated\n * @param userId string The user id (only serverside)\n * @returns\n */\n async updatePollOption(pollId: string, option: PollOptionData, userId?: string) {\n return await this.put<APIResponse & UpdatePollOptionAPIResponse>(\n this.baseURL + `/polls/${encodeURIComponent(pollId)}/options`,\n {\n ...option,\n ...(userId ? { user_id: userId } : {}),\n },\n );\n }\n\n /**\n * Delete a poll option\n * @param pollId string The poll id\n * @param optionId string The poll option id\n * @param userId string The user id (only serverside)\n * @returns {APIResponse} The poll option\n */\n async deletePollOption(pollId: string, optionId: string, userId?: string) {\n return await this.delete<APIResponse>(\n this.baseURL +\n `/polls/${encodeURIComponent(pollId)}/options/${encodeURIComponent(optionId)}`,\n userId ? { user_id: userId } : {},\n );\n }\n\n /**\n * Cast vote on a poll\n * @param messageId string The message id\n * @param pollId string The poll id\n * @param vote PollVoteData The vote that will be casted\n * @param userId string The user id (only serverside)\n * @returns {APIResponse & CastVoteAPIResponse} The poll vote\n */\n async castPollVote(\n messageId: string,\n pollId: string,\n vote: PollVoteData,\n userId?: string,\n ) {\n return await this.post<APIResponse & CastVoteAPIResponse>(\n this.baseURL +\n `/messages/${encodeURIComponent(messageId)}/polls/${encodeURIComponent(pollId)}/vote`,\n {\n vote,\n ...(userId ? { user_id: userId } : {}),\n },\n );\n }\n\n /**\n * Add a poll answer\n * @param messageId string The message id\n * @param pollId string The poll id\n * @param answerText string The answer text\n * @param userId string The user id (only serverside)\n */\n addPollAnswer(messageId: string, pollId: string, answerText: string, userId?: string) {\n return this.castPollVote(\n messageId,\n pollId,\n {\n answer_text: answerText,\n },\n userId,\n );\n }\n\n async removePollVote(\n messageId: string,\n pollId: string,\n voteId: string,\n userId?: string,\n ) {\n return await this.delete<APIResponse & { vote: PollVote }>(\n this.baseURL +\n `/messages/${encodeURIComponent(messageId)}/polls/${encodeURIComponent(pollId)}/vote/${encodeURIComponent(\n voteId,\n )}`,\n {\n ...(userId ? { user_id: userId } : {}),\n },\n );\n }\n\n /**\n * Queries polls\n * @param filter\n * @param sort\n * @param options Option object, {limit: 10, offset:0}\n * @param userId string The user id (only serverside)\n * @returns {APIResponse & QueryPollsResponse} The polls\n */\n async queryPolls(\n filter: QueryPollsFilters = {},\n sort: PollSort = [],\n options: QueryPollsOptions = {},\n userId?: string,\n ): Promise<APIResponse & QueryPollsResponse> {\n const q = userId ? `?user_id=${userId}` : '';\n return await this.post<APIResponse & QueryPollsResponse>(\n this.baseURL + `/polls/query${q}`,\n {\n filter,\n sort: normalizeQuerySort(sort),\n ...options,\n },\n );\n }\n\n /**\n * Queries poll votes\n * @param pollId\n * @param filter\n * @param sort\n * @param options Option object, {limit: 10, offset:0}\n * @param userId string The user id (only serverside)\n * @returns {APIResponse & PollVotesAPIResponse} The poll votes\n */\n async queryPollVotes(\n pollId: string,\n filter: QueryVotesFilters = {},\n sort: VoteSort = [],\n options: QueryVotesOptions = {},\n userId?: string,\n ): Promise<APIResponse & PollVotesAPIResponse> {\n const q = userId ? `?user_id=${userId}` : '';\n return await this.post<APIResponse & PollVotesAPIResponse>(\n this.baseURL + `/polls/${encodeURIComponent(pollId)}/votes${q}`,\n {\n filter,\n sort: normalizeQuerySort(sort),\n ...options,\n },\n );\n }\n\n /**\n * Queries poll answers\n * @param pollId\n * @param filter\n * @param sort\n * @param options Option object, {limit: 10, offset:0}\n * @param userId string The user id (only serverside)\n * @returns {APIResponse & PollAnswersAPIResponse} The poll votes\n */\n async queryPollAnswers(\n pollId: string,\n filter: QueryVotesFilters = {},\n sort: VoteSort = [],\n options: QueryVotesOptions = {},\n userId?: string,\n ): Promise<APIResponse & PollAnswersAPIResponse> {\n const q = userId ? `?user_id=${userId}` : '';\n return await this.post<APIResponse & PollAnswersAPIResponse>(\n this.baseURL + `/polls/${encodeURIComponent(pollId)}/votes${q}`,\n {\n filter: { ...filter, is_answer: true },\n sort: normalizeQuerySort(sort),\n ...options,\n },\n );\n }\n\n /**\n * Query message history\n * @param filter\n * @param sort\n * @param options Option object, {limit: 10}\n * @returns {APIResponse & QueryMessageHistoryResponse} The message histories\n */\n async queryMessageHistory(\n filter: QueryMessageHistoryFilters = {},\n sort: QueryMessageHistorySort = [],\n options: QueryMessageHistoryOptions = {},\n ): Promise<APIResponse & QueryMessageHistoryResponse> {\n return await this.post<APIResponse & QueryMessageHistoryResponse>(\n this.baseURL + '/messages/history',\n {\n filter,\n sort: normalizeQuerySort(sort),\n ...options,\n },\n );\n }\n\n /**\n * updateFlags - reviews/unflags flagged message\n *\n * @param {string[]} message_ids list of message IDs\n * @param {string} options Option object in case user ID is set to review all the flagged messages by the user\n * @param {string} reviewed_by user ID who reviewed the flagged message\n * @returns {APIResponse}\n */\n async updateFlags(\n message_ids: string[],\n reviewed_by: string,\n options: { user_id?: string } = {},\n ) {\n return await this.post<APIResponse>(\n this.baseURL + '/automod/v1/moderation/update_flags',\n {\n message_ids,\n reviewed_by,\n ...options,\n },\n );\n }\n\n /**\n * queryDrafts - Queries drafts for the current user\n *\n * @param {object} [options] Query options\n * @param {object} [options.filter] Filters for the query\n * @param {number} [options.sort] Sort parameters\n * @param {number} [options.limit] Limit the number of results\n * @param {string} [options.next] Pagination parameter\n * @param {string} [options.prev] Pagination parameter\n * @param {string} [options.user_id] Has to be provided when called server-side\n *\n * @return {Promise<APIResponse & { drafts: DraftResponse[]; next?: string }>} Response containing the drafts\n */\n async queryDrafts(\n options: Pager & {\n filter?: DraftFilters;\n sort?: DraftSort;\n user_id?: string;\n } = {},\n ) {\n const payload = {\n ...options,\n sort: options.sort ? normalizeQuerySort(options.sort) : undefined,\n };\n\n return await this.post<QueryDraftsResponse>(this.baseURL + '/drafts/query', payload);\n }\n\n /**\n * createReminder - Creates a reminder for a message\n *\n * @param {CreateReminderOptions} options The options for creating the reminder\n * @returns {Promise<ReminderAPIResponse>}\n */\n async createReminder({ messageId, ...options }: CreateReminderOptions) {\n return await this.post<ReminderAPIResponse>(\n `${this.baseURL}/messages/${messageId}/reminders`,\n options,\n );\n }\n\n /**\n * updateReminder - Updates an existing reminder for a message\n *\n * @param {UpdateReminderOptions} options The options for updating the reminder\n * @returns {Promise<ReminderAPIResponse>}\n */\n async updateReminder({ messageId, ...options }: UpdateReminderOptions) {\n return await this.patch<ReminderAPIResponse>(\n `${this.baseURL}/messages/${messageId}/reminders`,\n options,\n );\n }\n\n /**\n * deleteReminder - Deletes a reminder for a message\n *\n * @param {string} messageId The ID of the message whose reminder to delete\n * @param {string} [userId] Optional user ID, required for server-side operations\n * @returns {Promise<APIResponse>}\n */\n async deleteReminder(messageId: string, userId?: string): Promise<APIResponse> {\n return await this.delete<APIResponse>(\n `${this.baseURL}/messages/${messageId}/reminders`,\n userId ? { user_id: userId } : {},\n );\n }\n\n /**\n * queryReminders - Queries reminders based on given filters\n *\n * @param {QueryRemindersOptions} options The options for querying reminders\n * @returns {Promise<QueryRemindersResponse>}\n */\n async queryReminders({ filter, sort, ...rest }: QueryRemindersOptions = {}) {\n return await this.post<QueryRemindersResponse>(`${this.baseURL}/reminders/query`, {\n filter,\n sort: sort && normalizeQuerySort(sort),\n ...rest,\n });\n }\n\n /**\n * updateLocation - Updates a location\n *\n * @param location SharedLocationRequest the location data to update\n *\n * @returns {Promise<SharedLocationResponse>} The server response\n */\n async updateLocation(location: UpdateLocationPayload) {\n return await this.put<SharedLocationResponse>(\n this.baseURL + `/users/live_locations`,\n location,\n );\n }\n\n /**\n * uploadFile - Uploads a file to the configured storage (defaults to Stream CDN)\n *\n * @param {string|NodeJS.ReadableStream|Buffer|File} uri The file to upload\n * @param {string} [name] The name of the file\n * @param {string} [contentType] The content type of the file\n * @param {UserResponse} [user] Optional user information\n *\n * @return {Promise<SendFileAPIResponse>} Response containing the file URL\n */\n uploadFile(\n uri: string | NodeJS.ReadableStream | Buffer | File,\n name?: string,\n contentType?: string,\n user?: UserResponse,\n ) {\n return this.sendFile(`${this.baseURL}/uploads/file`, uri, name, contentType, user);\n }\n\n /**\n * uploadImage - Uploads an image to the configured storage (defaults to Stream CDN)\n *\n * @param {string|NodeJS.ReadableStream|File} uri The image to upload\n * @param {string} [name] The name of the image\n * @param {string} [contentType] The content type of the image\n * @param {UserResponse} [user] Optional user information\n *\n * @return {Promise<SendFileAPIResponse>} Response containing the image URL\n */\n uploadImage(\n uri: string | NodeJS.ReadableStream | File,\n name?: string,\n contentType?: string,\n user?: UserResponse,\n ) {\n return this.sendFile(`${this.baseURL}/uploads/image`, uri, name, contentType, user);\n }\n\n /**\n * deleteFile - Deletes a file from the configured storage\n *\n * @param {string} url The URL of the file to delete\n *\n * @return {Promise<APIResponse>} The server response\n */\n deleteFile(url: string) {\n return this.delete<APIResponse>(`${this.baseURL}/uploads/file`, { url });\n }\n\n /**\n * deleteImage - Deletes an image from the configured storage\n *\n * @param {string} url The URL of the image to delete\n *\n * @return {Promise<APIResponse>} The server response\n */\n deleteImage(url: string) {\n return this.delete<APIResponse>(`${this.baseURL}/uploads/image`, { url });\n }\n}\n", "import FormData from 'form-data';\nimport type {\n AscDesc,\n ChannelFilters,\n ChannelQueryOptions,\n ChannelSort,\n ChannelSortBase,\n LocalMessage,\n LocalMessageBase,\n Logger,\n Message,\n MessagePaginationOptions,\n MessageResponse,\n MessageResponseBase,\n MessageSet,\n OwnUserBase,\n OwnUserResponse,\n PromoteChannelParams,\n QueryChannelAPIResponse,\n ReactionGroupResponse,\n UpdatedMessage,\n UserResponse,\n} from './types';\nimport type { StreamChat } from './client';\nimport type { Channel } from './channel';\nimport type { AxiosRequestConfig } from 'axios';\nimport { LOCAL_MESSAGE_FIELDS, RESERVED_UPDATED_MESSAGE_FIELDS } from './constants';\n\n/**\n * logChatPromiseExecution - utility function for logging the execution of a promise..\n * use this when you want to run the promise and handle errors by logging a warning\n *\n * @param {Promise<T>} promise The promise you want to run and log\n * @param {string} name A descriptive name of what the promise does for log output\n *\n */\nexport function logChatPromiseExecution<T>(promise: Promise<T>, name: string) {\n promise.then().catch((error) => {\n console.warn(`failed to do ${name}, ran into error: `, error);\n });\n}\n\nexport const sleep = (m: number): Promise<void> => new Promise((r) => setTimeout(r, m));\n\nexport function isFunction(value: unknown): value is (...args: unknown[]) => unknown {\n return (\n typeof value === 'function' ||\n value instanceof Function ||\n Object.prototype.toString.call(value) === '[object Function]'\n );\n}\n\nexport const chatCodes = {\n TOKEN_EXPIRED: 40,\n WS_CLOSED_SUCCESS: 1000,\n};\n\nfunction isReadableStream(obj: unknown): obj is NodeJS.ReadStream {\n return (\n obj !== null &&\n typeof obj === 'object' &&\n ((obj as NodeJS.ReadStream).readable ||\n typeof (obj as NodeJS.ReadStream)._read === 'function')\n );\n}\n\nfunction isBuffer(obj: unknown): obj is Buffer {\n return (\n obj != null &&\n (obj as Buffer).constructor != null &&\n // @ts-expect-error expected\n typeof obj.constructor.isBuffer === 'function' &&\n // @ts-expect-error expected\n obj.constructor.isBuffer(obj)\n );\n}\n\nfunction isFileWebAPI(uri: unknown): uri is File {\n return typeof window !== 'undefined' && 'File' in window && uri instanceof File;\n}\n\nexport function isOwnUser(\n user?: OwnUserResponse | UserResponse,\n): user is OwnUserResponse {\n return (user as OwnUserResponse)?.total_unread_count !== undefined;\n}\n\nfunction isBlobWebAPI(uri: unknown): uri is Blob {\n return typeof window !== 'undefined' && 'Blob' in window && uri instanceof Blob;\n}\n\nexport function isOwnUserBaseProperty(property: string) {\n const ownUserBaseProperties: {\n [Property in keyof Required<OwnUserBase>]: boolean;\n } = {\n channel_mutes: true,\n devices: true,\n mutes: true,\n total_unread_count: true,\n unread_channels: true,\n unread_count: true,\n unread_threads: true,\n invisible: true,\n privacy_settings: true,\n roles: true,\n push_preferences: true,\n };\n\n return ownUserBaseProperties[property as keyof OwnUserBase];\n}\n\nexport function addFileToFormData(\n uri: string | NodeJS.ReadableStream | Buffer | File,\n name?: string,\n contentType?: string,\n) {\n const data = new FormData();\n\n if (isReadableStream(uri) || isBuffer(uri) || isFileWebAPI(uri) || isBlobWebAPI(uri)) {\n if (name) data.append('file', uri, name);\n else data.append('file', uri);\n } else {\n data.append('file', {\n uri,\n name: name || (uri as string).split('/').reverse()[0],\n contentType: contentType || undefined,\n type: contentType || undefined,\n });\n }\n\n return data;\n}\nexport function normalizeQuerySort<T extends Record<string, AscDesc | undefined>>(\n sort: T | T[],\n) {\n const sortFields: Array<{ direction: AscDesc; field: keyof T }> = [];\n const sortArr = Array.isArray(sort) ? sort : [sort];\n for (const item of sortArr) {\n const entries = Object.entries(item) as [keyof T, AscDesc][];\n if (entries.length > 1) {\n console.warn(\n \"client._buildSort() - multiple fields in a single sort object detected. Object's field order is not guaranteed\",\n );\n }\n for (const [field, direction] of entries) {\n sortFields.push({ field, direction });\n }\n }\n return sortFields;\n}\n\n/**\n * retryInterval - A retry interval which increases acc to number of failures\n *\n * @return {number} Duration to wait in milliseconds\n */\nexport function retryInterval(numberOfFailures: number) {\n // try to reconnect in 0.25-25 seconds (random to spread out the load from failures)\n const max = Math.min(500 + numberOfFailures * 2000, 25000);\n const min = Math.min(Math.max(250, (numberOfFailures - 1) * 2000), 25000);\n return Math.floor(Math.random() * (max - min) + min);\n}\n\nexport function randomId() {\n return generateUUIDv4();\n}\n\nfunction hex(bytes: Uint8Array): string {\n let s = '';\n for (let i = 0; i < bytes.length; i++) {\n s += bytes[i].toString(16).padStart(2, '0');\n }\n return s;\n}\n\n// https://tools.ietf.org/html/rfc4122\nexport function generateUUIDv4() {\n const bytes = getRandomBytes(16);\n bytes[6] = (bytes[6] & 0x0f) | 0x40; // version\n bytes[8] = (bytes[8] & 0xbf) | 0x80; // variant\n\n return (\n hex(bytes.subarray(0, 4)) +\n '-' +\n hex(bytes.subarray(4, 6)) +\n '-' +\n hex(bytes.subarray(6, 8)) +\n '-' +\n hex(bytes.subarray(8, 10)) +\n '-' +\n hex(bytes.subarray(10, 16))\n );\n}\n\nfunction getRandomValuesWithMathRandom(bytes: Uint8Array): void {\n const max = Math.pow(2, (8 * bytes.byteLength) / bytes.length);\n for (let i = 0; i < bytes.length; i++) {\n bytes[i] = Math.random() * max;\n }\n}\ndeclare const msCrypto: Crypto;\n\nconst getRandomValues = (() => {\n if (typeof crypto !== 'undefined' && typeof crypto?.getRandomValues !== 'undefined') {\n return crypto.getRandomValues.bind(crypto);\n } else if (typeof msCrypto !== 'undefined') {\n return msCrypto.getRandomValues.bind(msCrypto);\n } else {\n return getRandomValuesWithMathRandom;\n }\n})();\n\nfunction getRandomBytes(length: number): Uint8Array {\n const bytes = new Uint8Array(length);\n getRandomValues(bytes);\n return bytes;\n}\n\nexport function convertErrorToJson(err: Error) {\n const jsonObj = {} as Record<string, unknown>;\n\n if (!err) return jsonObj;\n\n try {\n Object.getOwnPropertyNames(err).forEach((key) => {\n jsonObj[key] = Object.getOwnPropertyDescriptor(err, key);\n });\n } catch (_) {\n return {\n error: 'failed to serialize the error',\n };\n }\n\n return jsonObj;\n}\n\n/**\n * isOnline safely return the navigator.online value for browser env\n * if navigator is not in global object, it always return true\n */\nexport function isOnline() {\n const nav =\n typeof navigator !== 'undefined'\n ? navigator\n : typeof window !== 'undefined' && window.navigator\n ? window.navigator\n : undefined;\n\n if (!nav) {\n console.warn(\n 'isOnline failed to access window.navigator and assume browser is online',\n );\n return true;\n }\n\n // RN navigator has undefined for onLine\n if (typeof nav.onLine !== 'boolean') {\n return true;\n }\n\n return nav.onLine;\n}\n\n/**\n * listenForConnectionChanges - Adds an event listener fired on browser going online or offline\n */\nexport function addConnectionEventListeners(cb: (e: Event) => void) {\n if (typeof window !== 'undefined' && window.addEventListener) {\n window.addEventListener('offline', cb);\n window.addEventListener('online', cb);\n }\n}\n\nexport function removeConnectionEventListeners(cb: (e: Event) => void) {\n if (typeof window !== 'undefined' && window.removeEventListener) {\n window.removeEventListener('offline', cb);\n window.removeEventListener('online', cb);\n }\n}\n\nexport const axiosParamsSerializer: AxiosRequestConfig['paramsSerializer'] = (params) => {\n const newParams = [];\n for (const k in params) {\n // Stream backend doesn't treat \"undefined\" value same as value not being present.\n // So, we need to skip the undefined values.\n if (params[k] === undefined) continue;\n\n if (Array.isArray(params[k]) || typeof params[k] === 'object') {\n newParams.push(`${k}=${encodeURIComponent(JSON.stringify(params[k]))}`);\n } else {\n newParams.push(`${k}=${encodeURIComponent(params[k])}`);\n }\n }\n\n return newParams.join('&');\n};\n\n/**\n * Takes the message object, parses the dates, sets `__html`\n * and sets the status to `received` if missing; returns a new LocalMessage object.\n *\n * @param {LocalMessage} message `LocalMessage` object\n */\nexport function formatMessage(\n message: MessageResponse | MessageResponseBase | LocalMessage,\n): LocalMessage {\n const toLocalMessageBase = (\n msg: MessageResponse | MessageResponseBase | LocalMessage | null | undefined,\n ): LocalMessageBase | null => {\n if (!msg) return null;\n return {\n ...msg,\n created_at: msg.created_at ? new Date(msg.created_at) : new Date(),\n deleted_at: msg.deleted_at ? new Date(msg.deleted_at) : null,\n pinned_at: msg.pinned_at ? new Date(msg.pinned_at) : null,\n reaction_groups: maybeGetReactionGroupsFallback(\n msg.reaction_groups,\n msg.reaction_counts,\n msg.reaction_scores,\n ),\n status: msg.status || 'received',\n updated_at: msg.updated_at ? new Date(msg.updated_at) : new Date(),\n };\n };\n\n return {\n ...toLocalMessageBase(message),\n error: (message as LocalMessage).error ?? null,\n quoted_message: toLocalMessageBase((message as MessageResponse).quoted_message),\n } as LocalMessage;\n}\n\n/**\n * @private\n *\n * Takes a LocalMessage, parses the dates back to strings,\n * and converts the message back to a MessageResponse.\n *\n * @param {MessageResponse} message `MessageResponse` object\n */\nexport function unformatMessage(message: LocalMessage): MessageResponse {\n const toMessageResponseBase = (\n msg: LocalMessage | null | undefined,\n ): MessageResponseBase | null => {\n if (!msg) return null;\n const newDateString = new Date().toISOString();\n return {\n ...msg,\n created_at: message.created_at ? message.created_at.toISOString() : newDateString,\n deleted_at: message.deleted_at ? message.deleted_at.toISOString() : undefined,\n pinned_at: message.pinned_at ? message.pinned_at.toISOString() : undefined,\n updated_at: message.updated_at ? message.updated_at.toISOString() : newDateString,\n };\n };\n\n return {\n ...toMessageResponseBase(message),\n quoted_message: toMessageResponseBase((message as LocalMessage).quoted_message),\n } as MessageResponse;\n}\n\nexport const localMessageToNewMessagePayload = (localMessage: LocalMessage): Message => {\n /* eslint-disable @typescript-eslint/no-unused-vars */\n const {\n // Remove all timestamp fields and client-specific fields.\n // Field pinned_at can therefore be earlier than created_at as new message payload can hold it.\n created_at,\n updated_at,\n deleted_at,\n // Client-specific fields\n error,\n status,\n // Reaction related fields\n latest_reactions,\n own_reactions,\n reaction_counts,\n reaction_scores,\n reply_count,\n // Message text related fields that shouldn't be in update\n command,\n html,\n i18n,\n quoted_message,\n mentioned_users,\n // Message content related fields\n ...messageFields\n } = localMessage;\n\n return {\n ...messageFields,\n pinned_at: messageFields.pinned_at?.toISOString(),\n mentioned_users: mentioned_users?.map((user) => user.id),\n };\n};\n\nexport const toUpdatedMessagePayload = (\n message: LocalMessage | Partial<MessageResponse>,\n): UpdatedMessage => {\n const reservedKeys = {\n ...RESERVED_UPDATED_MESSAGE_FIELDS,\n ...LOCAL_MESSAGE_FIELDS,\n } as const;\n\n const messageFields = Object.fromEntries(\n Object.entries(message).filter(\n ([key]) => !reservedKeys[key as keyof typeof reservedKeys],\n ),\n ) as UpdatedMessage;\n\n return {\n ...messageFields,\n pinned: !!message.pinned_at,\n mentioned_users: message.mentioned_users?.map((user) =>\n typeof user === 'string' ? user : user.id,\n ),\n };\n};\n\nexport const toDeletedMessage = ({\n message,\n deletedAt,\n hardDelete = false,\n}: {\n message: LocalMessage | LocalMessageBase;\n deletedAt: LocalMessage['deleted_at'];\n hardDelete: boolean;\n}) => {\n if (hardDelete) {\n /**\n * In case of hard delete, we need to strip down all text, html, attachments and all the custom properties on message\n * The hard-deleted message is kept in the UI until the messages are re-queried\n * FIXME: we are returning an object that does not match LocalMessage | LocalMessageBase\n */\n return {\n attachments: [],\n cid: message.cid,\n created_at: message.created_at,\n deleted_at: deletedAt,\n id: message.id,\n latest_reactions: [],\n mentioned_users: [],\n own_reactions: [],\n parent_id: message.parent_id,\n reply_count: message.reply_count,\n status: message.status,\n thread_participants: message.thread_participants,\n type: 'deleted' as const,\n updated_at: message.updated_at,\n user: message.user,\n };\n } else {\n return {\n ...message,\n attachments: [],\n type: 'deleted',\n deleted_at: deletedAt,\n };\n }\n};\n\nexport const deleteUserMessages = ({\n messages,\n user,\n hardDelete = false,\n deletedAt,\n}: {\n messages: Array<LocalMessage>;\n user: UserResponse;\n hardDelete: boolean;\n deletedAt: LocalMessage['deleted_at'];\n}) => {\n for (let i = 0; i < messages.length; i++) {\n const message = messages[i];\n if (message.user?.id === user.id) {\n messages[i] =\n message.type === 'deleted'\n ? message\n : (toDeletedMessage({ message, hardDelete, deletedAt }) as LocalMessage);\n }\n\n if (message.quoted_message?.user?.id === user.id) {\n messages[i].quoted_message =\n message.quoted_message.type === 'deleted'\n ? message.quoted_message\n : (toDeletedMessage({\n message: messages[i].quoted_message as LocalMessageBase,\n hardDelete,\n deletedAt,\n }) as LocalMessage);\n }\n }\n};\n\nexport const findIndexInSortedArray = <T, L>({\n needle,\n sortedArray,\n selectKey,\n selectValueToCompare = (e) => e,\n sortDirection = 'ascending',\n}: {\n needle: T;\n sortedArray: readonly T[];\n /**\n * In an array of objects (like messages), pick a unique property identifying\n * an element. It will be used to find a direct match for the needle element\n * in case compare values are not unique.\n *\n * @example\n * ```ts\n * selectKey: (message) => message.id\n * ```\n */\n selectKey?: (arrayElement: T) => string;\n /**\n * In an array of objects (like messages), pick a specific\n * property to compare the needle value to.\n *\n * @example\n * ```ts\n * selectValueToCompare: (message) => message.created_at.getTime()\n * ```\n */\n selectValueToCompare?: (arrayElement: T) => L | T;\n /**\n * @default ascending\n * @description\n * ```md\n * ascending - [1,2,3,4,5...]\n * descending - [...5,4,3,2,1]\n * ```\n */\n sortDirection?: 'ascending' | 'descending';\n}) => {\n if (!sortedArray.length) return 0;\n\n let left = 0;\n let right = sortedArray.length - 1;\n let middle = 0;\n\n const recalculateMiddle = () => {\n middle = Math.round((left + right) / 2);\n };\n\n const comparableNeedle = selectValueToCompare(needle);\n\n while (left <= right) {\n recalculateMiddle();\n\n const comparableMiddle = selectValueToCompare(sortedArray[middle]);\n\n if (\n (sortDirection === 'ascending' && comparableNeedle < comparableMiddle) ||\n (sortDirection === 'descending' && comparableNeedle >= comparableMiddle)\n ) {\n right = middle - 1;\n } else {\n left = middle + 1;\n }\n }\n\n // In case there are several array elements with the same comparable value, search around the insertion\n // point to possibly find an element with the same key. If found, prefer it.\n // This, for example, prevents duplication of messages with the same creation date.\n if (selectKey) {\n const needleKey = selectKey(needle);\n const step = sortDirection === 'ascending' ? -1 : +1;\n for (\n let i = left + step;\n 0 <= i &&\n i < sortedArray.length &&\n selectValueToCompare(sortedArray[i]) === comparableNeedle;\n i += step\n ) {\n if (selectKey(sortedArray[i]) === needleKey) {\n return i;\n }\n }\n }\n\n return left;\n};\n\nexport function addToMessageList<T extends LocalMessage>(\n messages: readonly T[],\n newMessage: T,\n timestampChanged = false,\n sortBy: 'pinned_at' | 'created_at' = 'created_at',\n addIfDoesNotExist = true,\n) {\n const addMessageToList = addIfDoesNotExist || timestampChanged;\n let newMessages = [...messages];\n\n // if created_at has changed, message should be filtered and re-inserted in correct order\n // slow op but usually this only happens for a message inserted to state before actual response with correct timestamp\n if (timestampChanged) {\n newMessages = newMessages.filter(\n (message) => !(message.id && newMessage.id === message.id),\n );\n }\n\n // for empty list just concat and return unless it's an update or deletion\n if (newMessages.length === 0 && addMessageToList) {\n return newMessages.concat(newMessage);\n } else if (newMessages.length === 0) {\n return newMessages;\n }\n\n // eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n const messageTime = newMessage[sortBy]!.getTime();\n // eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n const messageIsNewest = newMessages.at(-1)![sortBy]!.getTime() < messageTime;\n\n // if message is newer than last item in the list concat and return unless it's an update or deletion\n if (messageIsNewest && addMessageToList) {\n return newMessages.concat(newMessage);\n } else if (messageIsNewest) {\n return newMessages;\n }\n\n // find the closest index to push the new message\n const insertionIndex = findIndexInSortedArray({\n needle: newMessage,\n sortedArray: newMessages,\n sortDirection: 'ascending',\n // eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n selectValueToCompare: (m) => m[sortBy]!.getTime(),\n selectKey: (m) => m.id,\n });\n\n // message already exists and not filtered with timestampChanged, update and return\n if (\n !timestampChanged &&\n newMessage.id &&\n newMessages[insertionIndex] &&\n newMessage.id === newMessages[insertionIndex].id\n ) {\n newMessages[insertionIndex] = newMessage;\n return newMessages;\n }\n\n // do not add updated or deleted messages to the list if they already exist or come with a timestamp change\n if (addMessageToList) {\n newMessages.splice(insertionIndex, 0, newMessage);\n }\n\n return newMessages;\n}\n\nfunction maybeGetReactionGroupsFallback(\n groups: { [key: string]: ReactionGroupResponse } | null | undefined,\n counts: { [key: string]: number } | null | undefined,\n scores: { [key: string]: number } | null | undefined,\n): { [key: string]: ReactionGroupResponse } | null {\n if (groups) {\n return groups;\n }\n\n if (counts && scores) {\n const fallback: { [key: string]: ReactionGroupResponse } = {};\n\n for (const type of Object.keys(counts)) {\n fallback[type] = {\n count: counts[type],\n sum_scores: scores[type],\n };\n }\n\n return fallback;\n }\n\n return null;\n}\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport interface DebouncedFunc<T extends (...args: any[]) => any> {\n /**\n * Call the original function, but applying the debounce rules.\n *\n * If the debounced function can be run immediately, this calls it and returns its return\n * value.\n *\n * Otherwise, it returns the return value of the last invocation, or undefined if the debounced\n * function was not invoked yet.\n */\n (...args: Parameters<T>): ReturnType<T> | undefined;\n\n /**\n * Throw away any pending invocation of the debounced function.\n */\n cancel(): void;\n\n /**\n * If there is a pending invocation of the debounced function, invoke it immediately and return\n * its return value.\n *\n * Otherwise, return the value from the last invocation, or undefined if the debounced function\n * was never invoked.\n */\n flush(): ReturnType<T> | undefined;\n}\n\n// works exactly the same as lodash.debounce\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport const debounce = <T extends (...args: any[]) => any>(\n fn: T,\n timeout = 0,\n { leading = false, trailing = true }: { leading?: boolean; trailing?: boolean } = {},\n): DebouncedFunc<T> => {\n let runningTimeout: null | NodeJS.Timeout = null;\n let argsForTrailingExecution: Parameters<T> | null = null;\n let lastResult: ReturnType<T> | undefined;\n\n const debouncedFn = (...args: Parameters<T>) => {\n if (runningTimeout) {\n clearTimeout(runningTimeout);\n } else if (leading) {\n lastResult = fn(...args);\n }\n if (trailing) argsForTrailingExecution = args;\n\n const timeoutHandler = () => {\n if (argsForTrailingExecution) {\n lastResult = fn(...argsForTrailingExecution);\n argsForTrailingExecution = null;\n }\n runningTimeout = null;\n };\n\n runningTimeout = setTimeout(timeoutHandler, timeout);\n return lastResult;\n };\n\n debouncedFn.cancel = () => {\n if (runningTimeout) clearTimeout(runningTimeout);\n };\n\n debouncedFn.flush = () => {\n if (runningTimeout) {\n clearTimeout(runningTimeout);\n runningTimeout = null;\n if (argsForTrailingExecution) {\n lastResult = fn(...argsForTrailingExecution);\n }\n }\n return lastResult;\n };\n return debouncedFn;\n};\n\n// works exactly the same as lodash.throttle\nexport const throttle = <T extends (...args: unknown[]) => unknown>(\n fn: T,\n timeout = 200,\n { leading = true, trailing = false }: { leading?: boolean; trailing?: boolean } = {},\n) => {\n let runningTimeout: null | NodeJS.Timeout = null;\n let storedArgs: Parameters<T> | null = null;\n\n return (...args: Parameters<T>) => {\n if (runningTimeout) {\n if (trailing) storedArgs = args;\n return;\n }\n\n if (leading) fn(...args);\n\n const timeoutHandler = () => {\n if (storedArgs) {\n fn(...storedArgs);\n storedArgs = null;\n runningTimeout = setTimeout(timeoutHandler, timeout);\n\n return;\n }\n\n runningTimeout = null;\n };\n\n runningTimeout = setTimeout(timeoutHandler, timeout);\n };\n};\n\nconst get = <T>(obj: T, path: string): unknown =>\n path.split('.').reduce<unknown>((acc, key) => {\n if (acc && typeof acc === 'object' && key in acc) {\n return (acc as Record<string, unknown>)[key];\n }\n return undefined;\n }, obj);\n\n// works exactly the same as lodash.uniqBy\nexport const uniqBy = <T>(\n array: T[] | unknown,\n iteratee: ((item: T) => unknown) | keyof T,\n): T[] => {\n if (!Array.isArray(array)) return [];\n\n const seen = new Set<unknown>();\n return array.filter((item) => {\n const key =\n typeof iteratee === 'function' ? iteratee(item) : get(item, iteratee as string);\n if (seen.has(key)) return false;\n seen.add(key);\n return true;\n });\n};\n\ntype MessagePaginationUpdatedParams = {\n parentSet: MessageSet;\n requestedPageSize: number;\n returnedPage: MessageResponse[];\n logger?: Logger;\n messagePaginationOptions?: MessagePaginationOptions;\n};\n\nexport function binarySearchByDateEqualOrNearestGreater(\n array: {\n created_at?: string;\n }[],\n targetDate: Date,\n): number {\n let left = 0;\n let right = array.length - 1;\n\n while (left <= right) {\n const mid = Math.floor((left + right) / 2);\n const midCreatedAt = array[mid].created_at;\n if (!midCreatedAt) {\n left += 1;\n continue;\n }\n const midDate = new Date(midCreatedAt);\n\n if (midDate.getTime() === targetDate.getTime()) {\n return mid;\n } else if (midDate.getTime() < targetDate.getTime()) {\n left = mid + 1;\n } else {\n right = mid - 1;\n }\n }\n\n return left;\n}\n\nconst messagePaginationCreatedAtAround = ({\n parentSet,\n requestedPageSize,\n returnedPage,\n messagePaginationOptions,\n}: MessagePaginationUpdatedParams) => {\n const newPagination = { ...parentSet.pagination };\n if (!messagePaginationOptions?.created_at_around) return newPagination;\n let hasPrev;\n let hasNext;\n let updateHasPrev;\n let updateHasNext;\n const createdAtAroundDate = new Date(messagePaginationOptions.created_at_around);\n const [firstPageMsg, lastPageMsg] = [returnedPage[0], returnedPage.slice(-1)[0]];\n\n // expect ASC order (from oldest to newest)\n const wholePageHasNewerMessages =\n !!firstPageMsg?.created_at && new Date(firstPageMsg.created_at) > createdAtAroundDate;\n const wholePageHasOlderMessages =\n !!lastPageMsg?.created_at && new Date(lastPageMsg.created_at) < createdAtAroundDate;\n\n const requestedPageSizeNotMet =\n requestedPageSize > parentSet.messages.length &&\n requestedPageSize > returnedPage.length;\n const noMoreMessages =\n (requestedPageSize > parentSet.messages.length ||\n parentSet.messages.length >= returnedPage.length) &&\n requestedPageSize > returnedPage.length;\n\n if (wholePageHasNewerMessages) {\n hasPrev = false;\n updateHasPrev = true;\n if (requestedPageSizeNotMet) {\n hasNext = false;\n updateHasNext = true;\n }\n } else if (wholePageHasOlderMessages) {\n hasNext = false;\n updateHasNext = true;\n if (requestedPageSizeNotMet) {\n hasPrev = false;\n updateHasPrev = true;\n }\n } else if (noMoreMessages) {\n hasNext = hasPrev = false;\n updateHasPrev = updateHasNext = true;\n } else {\n const [firstPageMsgIsFirstInSet, lastPageMsgIsLastInSet] = [\n firstPageMsg?.id && firstPageMsg.id === parentSet.messages[0]?.id,\n lastPageMsg?.id && lastPageMsg.id === parentSet.messages.slice(-1)[0]?.id,\n ];\n updateHasPrev = firstPageMsgIsFirstInSet;\n updateHasNext = lastPageMsgIsLastInSet;\n const midPointByCount = Math.floor(returnedPage.length / 2);\n const midPointByCreationDate = binarySearchByDateEqualOrNearestGreater(\n returnedPage,\n createdAtAroundDate,\n );\n\n if (midPointByCreationDate !== -1) {\n hasPrev = midPointByCount <= midPointByCreationDate;\n hasNext = midPointByCount >= midPointByCreationDate;\n }\n }\n\n if (updateHasPrev && typeof hasPrev !== 'undefined') newPagination.hasPrev = hasPrev;\n if (updateHasNext && typeof hasNext !== 'undefined') newPagination.hasNext = hasNext;\n\n return newPagination;\n};\n\nconst messagePaginationIdAround = ({\n parentSet,\n requestedPageSize,\n returnedPage,\n messagePaginationOptions,\n}: MessagePaginationUpdatedParams) => {\n const newPagination = { ...parentSet.pagination };\n const { id_around } = messagePaginationOptions || {};\n if (!id_around) return newPagination;\n let hasPrev;\n let hasNext;\n\n const [firstPageMsg, lastPageMsg] = [returnedPage[0], returnedPage.slice(-1)[0]];\n const [firstPageMsgIsFirstInSet, lastPageMsgIsLastInSet] = [\n firstPageMsg?.id === parentSet.messages[0]?.id,\n lastPageMsg?.id === parentSet.messages.slice(-1)[0]?.id,\n ];\n let updateHasPrev = firstPageMsgIsFirstInSet;\n let updateHasNext = lastPageMsgIsLastInSet;\n\n const midPoint = Math.floor(returnedPage.length / 2);\n const noMoreMessages =\n (requestedPageSize > parentSet.messages.length ||\n parentSet.messages.length >= returnedPage.length) &&\n requestedPageSize > returnedPage.length;\n\n if (noMoreMessages) {\n hasNext = hasPrev = false;\n updateHasPrev = updateHasNext = true;\n } else if (!returnedPage[midPoint]) {\n return newPagination;\n } else if (returnedPage[midPoint].id === id_around) {\n hasPrev = hasNext = true;\n } else {\n let targetMsg;\n const halves = [returnedPage.slice(0, midPoint), returnedPage.slice(midPoint)];\n hasPrev = hasNext = true;\n for (let i = 0; i < halves.length; i++) {\n targetMsg = halves[i].find((message) => message.id === id_around);\n if (targetMsg && i === 0) {\n hasPrev = false;\n }\n if (targetMsg && i === 1) {\n hasNext = false;\n }\n }\n }\n\n if (updateHasPrev && typeof hasPrev !== 'undefined') newPagination.hasPrev = hasPrev;\n if (updateHasNext && typeof hasNext !== 'undefined') newPagination.hasNext = hasNext;\n\n return newPagination;\n};\n\nconst messagePaginationLinear = ({\n parentSet,\n requestedPageSize,\n returnedPage,\n messagePaginationOptions,\n}: MessagePaginationUpdatedParams) => {\n const newPagination = { ...parentSet.pagination };\n\n let hasPrev;\n let hasNext;\n\n const [firstPageMsg, lastPageMsg] = [returnedPage[0], returnedPage.slice(-1)[0]];\n const [firstPageMsgIsFirstInSet, lastPageMsgIsLastInSet] = [\n firstPageMsg?.id && firstPageMsg.id === parentSet.messages[0]?.id,\n lastPageMsg?.id && lastPageMsg.id === parentSet.messages.slice(-1)[0]?.id,\n ];\n\n const queriedNextMessages =\n messagePaginationOptions &&\n (messagePaginationOptions.created_at_after_or_equal ||\n messagePaginationOptions.created_at_after ||\n messagePaginationOptions.id_gt ||\n messagePaginationOptions.id_gte);\n\n const queriedPrevMessages =\n typeof messagePaginationOptions === 'undefined'\n ? true\n : messagePaginationOptions.created_at_before_or_equal ||\n messagePaginationOptions.created_at_before ||\n messagePaginationOptions.id_lt ||\n messagePaginationOptions.id_lte ||\n messagePaginationOptions.offset;\n\n const containsUnrecognizedOptionsOnly =\n !queriedNextMessages &&\n !queriedPrevMessages &&\n !messagePaginationOptions?.id_around &&\n !messagePaginationOptions?.created_at_around;\n\n const hasMore = returnedPage.length >= requestedPageSize;\n\n if (typeof queriedPrevMessages !== 'undefined' || containsUnrecognizedOptionsOnly) {\n hasPrev = hasMore;\n }\n if (typeof queriedNextMessages !== 'undefined') {\n hasNext = hasMore;\n }\n const returnedPageIsEmpty = returnedPage.length === 0;\n\n if ((firstPageMsgIsFirstInSet || returnedPageIsEmpty) && typeof hasPrev !== 'undefined')\n newPagination.hasPrev = hasPrev;\n if ((lastPageMsgIsLastInSet || returnedPageIsEmpty) && typeof hasNext !== 'undefined')\n newPagination.hasNext = hasNext;\n\n return newPagination;\n};\n\nexport const messageSetPagination = (params: MessagePaginationUpdatedParams) => {\n const messagesFilteredLocally = params.returnedPage.filter(({ shadowed }) => shadowed);\n if (\n params.parentSet.messages.length + messagesFilteredLocally.length <\n params.returnedPage.length\n ) {\n params.logger?.(\n 'error',\n 'Corrupted message set state: parent set size < returned page size',\n );\n return params.parentSet.pagination;\n }\n\n if (params.messagePaginationOptions?.created_at_around) {\n return messagePaginationCreatedAtAround(params);\n } else if (params.messagePaginationOptions?.id_around) {\n return messagePaginationIdAround(params);\n } else {\n return messagePaginationLinear(params);\n }\n};\n\n/**\n * A utility object used to prevent duplicate invocation of channel.watch() to be triggered when\n * 'notification.message_new' and 'notification.added_to_channel' events arrive at the same time.\n */\nconst WATCH_QUERY_IN_PROGRESS_FOR_CHANNEL: Record<\n string,\n Promise<QueryChannelAPIResponse> | undefined\n> = {};\n\ntype GetChannelParams = {\n client: StreamChat;\n channel?: Channel;\n id?: string;\n members?: string[];\n options?: ChannelQueryOptions;\n type?: string;\n};\n/**\n * Calls channel.watch() if it was not already recently called. Waits for watch promise to resolve even if it was invoked previously.\n * If the channel is not passed as a property, it will get it either by its channel.cid or by its members list and do the same.\n * @param client\n * @param members\n * @param options\n * @param type\n * @param id\n * @param channel\n */\nexport const getAndWatchChannel = async ({\n channel,\n client,\n id,\n members,\n options,\n type,\n}: GetChannelParams) => {\n if (!channel && !type) {\n throw new Error('Channel or channel type have to be provided to query a channel.');\n }\n\n // unfortunately typescript is not able to infer that if (!channel && !type) === false, then channel or type has to be truthy\n // eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n const channelToWatch = channel || client.channel(type!, id, { members });\n\n // need to keep as with call to channel.watch the id can be changed from undefined to an actual ID generated server-side\n const originalCid = channelToWatch.id\n ? channelToWatch.cid\n : members && members.length\n ? generateChannelTempCid(channelToWatch.type, members)\n : undefined;\n\n if (!originalCid) {\n throw new Error(\n 'Channel ID or channel members array have to be provided to query a channel.',\n );\n }\n\n const queryPromise = WATCH_QUERY_IN_PROGRESS_FOR_CHANNEL[originalCid];\n\n if (queryPromise) {\n await queryPromise;\n } else {\n try {\n WATCH_QUERY_IN_PROGRESS_FOR_CHANNEL[originalCid] = channelToWatch.watch(options);\n await WATCH_QUERY_IN_PROGRESS_FOR_CHANNEL[originalCid];\n } finally {\n delete WATCH_QUERY_IN_PROGRESS_FOR_CHANNEL[originalCid];\n }\n }\n\n return channelToWatch;\n};\n\n/**\n * Generates a temporary channel.cid for channels created without ID, as they need to be referenced\n * by an identifier until the back-end generates the final ID. The cid is generated by its member IDs\n * which are sorted and can be recreated the same every time given the same arguments.\n * @param channelType\n * @param members\n */\nexport const generateChannelTempCid = (channelType: string, members: string[]) => {\n if (!members) return;\n const membersStr = [...members].sort().join(',');\n if (!membersStr) return;\n return `${channelType}:!members-${membersStr}`;\n};\n\n/**\n * Checks if a channel is pinned or not. Will return true only if channel.state.membership.pinned_at exists.\n * @param channel\n */\nexport const isChannelPinned = (channel: Channel) => {\n if (!channel) return false;\n\n const member = channel.state.membership;\n\n return !!member?.pinned_at;\n};\n\n/**\n * Checks if a channel is archived or not. Will return true only if channel.state.membership.archived_at exists.\n * @param channel\n */\nexport const isChannelArchived = (channel: Channel) => {\n if (!channel) return false;\n\n const member = channel.state.membership;\n\n return !!member?.archived_at;\n};\n\n/**\n * A utility that tells us whether we should consider archived channels or not based\n * on filters. Will return true only if filters.archived exists and is a boolean value.\n * @param filters\n */\nexport const shouldConsiderArchivedChannels = (filters: ChannelFilters) => {\n if (!filters) return false;\n\n return typeof filters.archived === 'boolean';\n};\n\n/**\n * Extracts the value of the sort parameter at a given index, for a targeted key. Can\n * handle both array and object versions of sort. Will return null if the index/key\n * combination does not exist.\n * @param atIndex - the index at which we'll examine the sort value, if it's an array one\n * @param sort - the sort value - both array and object notations are accepted\n * @param targetKey - the target key which needs to exist for the sort at a certain index\n */\nexport const extractSortValue = ({\n atIndex,\n sort,\n targetKey,\n}: {\n atIndex: number;\n targetKey: keyof ChannelSortBase;\n sort?: ChannelSort;\n}) => {\n if (!sort) return null;\n let option: null | ChannelSortBase = null;\n\n if (Array.isArray(sort)) {\n option = sort[atIndex] ?? null;\n } else {\n let index = 0;\n for (const key in sort) {\n if (index !== atIndex) {\n index++;\n continue;\n }\n\n if (key !== targetKey) {\n return null;\n }\n\n option = sort;\n\n break;\n }\n }\n\n return option?.[targetKey] ?? null;\n};\n\n/**\n * Returns true only if `{ pinned_at: -1 }` or `{ pinned_at: 1 }` option is first within the `sort` array.\n */\nexport const shouldConsiderPinnedChannels = (sort: ChannelSort) => {\n const value = findPinnedAtSortOrder({ sort });\n\n if (typeof value !== 'number') return false;\n\n return Math.abs(value) === 1;\n};\n\n/**\n * Checks whether the sort value of type object contains a pinned_at value or if\n * an array sort value type has the first value be an object containing pinned_at.\n * @param sort\n */\nexport const findPinnedAtSortOrder = ({ sort }: { sort: ChannelSort }) =>\n extractSortValue({\n atIndex: 0,\n sort,\n targetKey: 'pinned_at',\n });\n\n/**\n * Finds the index of the last consecutively pinned channel, starting from the start of the\n * array. Will not consider any pinned channels after the contiguous subsequence at the\n * start of the array.\n * @param channels\n */\nexport const findLastPinnedChannelIndex = ({ channels }: { channels: Channel[] }) => {\n let lastPinnedChannelIndex: number | null = null;\n\n for (const channel of channels) {\n if (!isChannelPinned(channel)) break;\n\n if (typeof lastPinnedChannelIndex === 'number') {\n lastPinnedChannelIndex++;\n } else {\n lastPinnedChannelIndex = 0;\n }\n }\n\n return lastPinnedChannelIndex;\n};\n\n/**\n * A utility used to move a channel towards the beginning of a list of channels (promote it to a higher position). It\n * considers pinned channels in the process if needed and makes sure to only update the list reference if the list\n * should actually change. It will try to move the channel as high as it can within the list.\n * @param channels - the list of channels we want to modify\n * @param channelToMove - the channel we want to promote\n * @param channelToMoveIndexWithinChannels - optionally, the index of the channel we want to move if we know it (will skip a manual check)\n * @param sort - the sort value used to check for pinned channels\n */\nexport const promoteChannel = ({\n channels,\n channelToMove,\n channelToMoveIndexWithinChannels,\n sort,\n}: PromoteChannelParams) => {\n // get index of channel to move up\n const targetChannelIndex =\n channelToMoveIndexWithinChannels ??\n channels.findIndex((channel) => channel.cid === channelToMove.cid);\n\n const targetChannelExistsWithinList = targetChannelIndex >= 0;\n const targetChannelAlreadyAtTheTop = targetChannelIndex === 0;\n\n // pinned channels should not move within the list based on recent activity, channels which\n // receive messages and are not pinned should move upwards but only under the last pinned channel\n // in the list\n const considerPinnedChannels = shouldConsiderPinnedChannels(sort);\n const isTargetChannelPinned = isChannelPinned(channelToMove);\n\n if (targetChannelAlreadyAtTheTop || (considerPinnedChannels && isTargetChannelPinned)) {\n return channels;\n }\n\n const newChannels = [...channels];\n\n // target channel index is known, remove it from the list\n if (targetChannelExistsWithinList) {\n newChannels.splice(targetChannelIndex, 1);\n }\n\n // as position of pinned channels has to stay unchanged, we need to\n // find last pinned channel in the list to move the target channel after\n let lastPinnedChannelIndex: number | null = null;\n if (considerPinnedChannels) {\n lastPinnedChannelIndex = findLastPinnedChannelIndex({ channels: newChannels });\n }\n\n // re-insert it at the new place (to specific index if pinned channels are considered)\n newChannels.splice(\n typeof lastPinnedChannelIndex === 'number' ? lastPinnedChannelIndex + 1 : 0,\n 0,\n channelToMove,\n );\n\n return newChannels;\n};\n\nexport const isDate = (value: unknown): value is Date => !!(value as Date).getTime;\n\nexport const isLocalMessage = (message: unknown): message is LocalMessage =>\n isDate((message as LocalMessage).created_at);\n\nexport const runDetached = <T>(\n callback: Promise<void | T>,\n options?: {\n context?: string;\n onSuccessCallback?: (res: T | void) => void | Promise<void>;\n onErrorCallback?: (error: Error) => void | Promise<void>;\n },\n) => {\n const { context, onSuccessCallback = () => undefined, onErrorCallback } = options ?? {};\n const defaultOnError = (error: Error) => {\n console.log(`An error has occurred in context ${context}: ${error}`);\n };\n const onError = onErrorCallback ?? defaultOnError;\n\n let promise = callback;\n\n if (onSuccessCallback) {\n promise = promise.then(onSuccessCallback);\n }\n\n promise.catch(onError);\n};\n", "export const DEFAULT_QUERY_CHANNELS_MESSAGE_LIST_PAGE_SIZE = 25;\nexport const DEFAULT_QUERY_CHANNEL_MESSAGE_LIST_PAGE_SIZE = 100;\nexport const DEFAULT_MESSAGE_SET_PAGINATION = { hasNext: false, hasPrev: false };\nexport const DEFAULT_UPLOAD_SIZE_LIMIT_BYTES = 100 * 1024 * 1024; // 100 MB\nexport const API_MAX_FILES_ALLOWED_PER_MESSAGE = 10;\nexport const MAX_CHANNEL_MEMBER_COUNT_IN_CHANNEL_QUERY = 100;\nexport const RESERVED_UPDATED_MESSAGE_FIELDS = {\n // Dates should not be converted back to ISO strings as JS looses precision on them (milliseconds)\n created_at: true,\n deleted_at: true,\n pinned_at: true,\n updated_at: true,\n command: true,\n // Back-end enriches these fields\n mentioned_users: true,\n quoted_message: true,\n // Client-specific fields\n latest_reactions: true,\n own_reactions: true,\n reaction_counts: true,\n reply_count: true,\n // Message text related fields that shouldn't be in update\n i18n: true,\n type: true,\n html: true,\n __html: true,\n user: true,\n} as const;\nexport const LOCAL_MESSAGE_FIELDS = { error: true } as const;\nexport const DEFAULT_QUERY_CHANNELS_RETRY_COUNT = 3;\nexport const DEFAULT_QUERY_CHANNELS_MS_BETWEEN_RETRIES = 1000; // 1 second\n", "import type { Channel } from './channel';\nimport type {\n ChannelMemberResponse,\n Event,\n LocalMessage,\n MessageResponse,\n MessageResponseBase,\n MessageSet,\n MessageSetType,\n PendingMessageResponse,\n ReactionResponse,\n UserResponse,\n} from './types';\nimport {\n deleteUserMessages as _deleteUserMessages,\n addToMessageList,\n formatMessage,\n} from './utils';\nimport { DEFAULT_MESSAGE_SET_PAGINATION } from './constants';\n\ntype ChannelReadStatus = Record<\n string,\n {\n last_read: Date;\n unread_messages: number;\n user: UserResponse;\n first_unread_message_id?: string;\n last_read_message_id?: string;\n }\n>;\n\n/**\n * ChannelState - A container class for the channel state.\n */\nexport class ChannelState {\n _channel: Channel;\n watcher_count: number;\n typing: Record<string, Event>;\n read: ChannelReadStatus;\n pinnedMessages: Array<ReturnType<ChannelState['formatMessage']>>;\n pending_messages: Array<PendingMessageResponse>;\n threads: Record<string, Array<ReturnType<ChannelState['formatMessage']>>>;\n mutedUsers: Array<UserResponse>;\n watchers: Record<string, UserResponse>;\n members: Record<string, ChannelMemberResponse>;\n unreadCount: number;\n membership: ChannelMemberResponse;\n last_message_at: Date | null;\n /**\n * Flag which indicates if channel state contain latest/recent messages or no.\n * This flag should be managed by UI sdks using a setter - setIsUpToDate.\n * When false, any new message (received by websocket event - message.new) will not\n * be pushed on to message list.\n */\n isUpToDate: boolean;\n /**\n * Disjoint lists of messages\n * Users can jump in the message list (with searching) and this can result in disjoint lists of messages\n * The state manages these lists and merges them when lists overlap\n * The messages array contains the currently active set\n */\n messageSets: MessageSet[] = [];\n\n constructor(channel: Channel) {\n this._channel = channel;\n this.watcher_count = 0;\n this.typing = {};\n this.read = {};\n this.initMessages();\n this.pinnedMessages = [];\n this.pending_messages = [];\n this.threads = {};\n // a list of users to hide messages from\n this.mutedUsers = [];\n this.watchers = {};\n this.members = {};\n this.membership = {};\n this.unreadCount = 0;\n /**\n * Flag which indicates if channel state contain latest/recent messages or no.\n * This flag should be managed by UI sdks using a setter - setIsUpToDate.\n * When false, any new message (received by websocket event - message.new) will not\n * be pushed on to message list.\n */\n this.isUpToDate = true;\n this.last_message_at =\n channel?.state?.last_message_at != null\n ? new Date(channel.state.last_message_at)\n : null;\n }\n\n get messages() {\n return this.messageSets.find((s) => s.isCurrent)?.messages || [];\n }\n\n set messages(messages: Array<ReturnType<ChannelState['formatMessage']>>) {\n const index = this.messageSets.findIndex((s) => s.isCurrent);\n this.messageSets[index].messages = messages;\n }\n\n /**\n * The list of latest messages\n * The messages array not always contains the latest messages (for example if a user searched for an earlier message, that is in a different message set)\n */\n get latestMessages() {\n return this.messageSets.find((s) => s.isLatest)?.messages || [];\n }\n\n set latestMessages(messages: Array<ReturnType<ChannelState['formatMessage']>>) {\n const index = this.messageSets.findIndex((s) => s.isLatest);\n this.messageSets[index].messages = messages;\n }\n\n get messagePagination() {\n return (\n this.messageSets.find((s) => s.isCurrent)?.pagination ||\n DEFAULT_MESSAGE_SET_PAGINATION\n );\n }\n\n /**\n * addMessageSorted - Add a message to the state\n *\n * @param {MessageResponse} newMessage A new message\n * @param {boolean} timestampChanged Whether updating a message with changed created_at value.\n * @param {boolean} addIfDoesNotExist Add message if it is not in the list, used to prevent out of order updated messages from being added.\n * @param {MessageSetType} messageSetToAddToIfDoesNotExist Which message set to add to if message is not in the list (only used if addIfDoesNotExist is true)\n */\n addMessageSorted(\n newMessage: MessageResponse | LocalMessage,\n timestampChanged = false,\n addIfDoesNotExist = true,\n messageSetToAddToIfDoesNotExist: MessageSetType = 'latest',\n ) {\n return this.addMessagesSorted(\n [newMessage],\n timestampChanged,\n false,\n addIfDoesNotExist,\n messageSetToAddToIfDoesNotExist,\n );\n }\n\n /**\n * Takes the message object, parses the dates, sets `__html`\n * and sets the status to `received` if missing; returns a new message object.\n *\n * @param {MessageResponse} message `MessageResponse` object\n */\n formatMessage = (message: MessageResponse | MessageResponseBase | LocalMessage) =>\n formatMessage(message);\n\n /**\n * addMessagesSorted - Add the list of messages to state and resorts the messages\n *\n * @param {Array<MessageResponse>} newMessages A list of messages\n * @param {boolean} timestampChanged Whether updating messages with changed created_at value.\n * @param {boolean} initializing Whether channel is being initialized.\n * @param {boolean} addIfDoesNotExist Add message if it is not in the list, used to prevent out of order updated messages from being added.\n * @param {MessageSetType} messageSetToAddToIfDoesNotExist Which message set to add to if messages are not in the list (only used if addIfDoesNotExist is true)\n *\n */\n addMessagesSorted(\n newMessages: (MessageResponse | LocalMessage)[],\n timestampChanged = false,\n initializing = false,\n addIfDoesNotExist = true,\n messageSetToAddToIfDoesNotExist: MessageSetType = 'current',\n ) {\n const { messagesToAdd, targetMessageSetIndex } = this.findTargetMessageSet(\n newMessages,\n addIfDoesNotExist,\n messageSetToAddToIfDoesNotExist,\n );\n\n for (let i = 0; i < messagesToAdd.length; i += 1) {\n const isFromShadowBannedUser = messagesToAdd[i].shadowed;\n if (isFromShadowBannedUser) {\n continue;\n }\n // If message is already formatted we can skip the tasks below\n // This will be true for messages that are already present at the state -> this happens when we perform merging of message sets\n // This will be also true for message previews used by some SDKs\n const isMessageFormatted = messagesToAdd[i].created_at instanceof Date;\n let message: ReturnType<ChannelState['formatMessage']>;\n if (isMessageFormatted) {\n message = messagesToAdd[i] as ReturnType<ChannelState['formatMessage']>;\n } else {\n message = this.formatMessage(messagesToAdd[i]);\n\n if (message.user && this._channel?.cid) {\n /**\n * Store the reference to user for this channel, so that when we have to\n * handle updates to user, we can use the reference map, to determine which\n * channels need to be updated with updated user object.\n */\n this._channel\n .getClient()\n .state.updateUserReference(message.user, this._channel.cid);\n }\n\n if (initializing && message.id && this.threads[message.id]) {\n // If we are initializing the state of channel (e.g., in case of connection recovery),\n // then in that case we remove thread related to this message from threads object.\n // This way we can ensure that we don't have any stale data in thread object\n // and consumer can refetch the replies.\n delete this.threads[message.id];\n }\n\n if (!this.last_message_at) {\n this.last_message_at = new Date(message.created_at.getTime());\n }\n\n if (message.created_at.getTime() > this.last_message_at.getTime()) {\n this.last_message_at = new Date(message.created_at.getTime());\n }\n }\n\n // update or append the messages...\n const parentID = message.parent_id;\n\n // add to the given message set\n if ((!parentID || message.show_in_channel) && targetMessageSetIndex !== -1) {\n this.messageSets[targetMessageSetIndex].messages = this._addToMessageList(\n this.messageSets[targetMessageSetIndex].messages,\n message,\n timestampChanged,\n 'created_at',\n addIfDoesNotExist,\n );\n }\n\n /**\n * Add message to thread if applicable and the message\n * was added when querying for replies, or the thread already exits.\n * This is to prevent the thread state from getting out of sync if\n * a thread message is shown in channel but older than the newest thread\n * message. This situation can result in a thread state where a random\n * message is \"oldest\" message, and newer messages are therefore not loaded.\n * This can also occur if an old thread message is updated.\n */\n if (parentID && !initializing) {\n const thread = this.threads[parentID] || [];\n this.threads[parentID] = this._addToMessageList(\n thread,\n message,\n timestampChanged,\n 'created_at',\n addIfDoesNotExist,\n );\n }\n }\n\n return {\n messageSet: this.messageSets[targetMessageSetIndex],\n };\n }\n\n /**\n * addPinnedMessages - adds messages in pinnedMessages property\n *\n * @param {Array<MessageResponse>} pinnedMessages A list of pinned messages\n *\n */\n addPinnedMessages(pinnedMessages: MessageResponse[]) {\n for (let i = 0; i < pinnedMessages.length; i += 1) {\n this.addPinnedMessage(pinnedMessages[i]);\n }\n }\n\n /**\n * addPinnedMessage - adds message in pinnedMessages\n *\n * @param {MessageResponse} pinnedMessage message to update\n *\n */\n addPinnedMessage(pinnedMessage: MessageResponse) {\n this.pinnedMessages = this._addToMessageList(\n this.pinnedMessages,\n this.formatMessage(pinnedMessage),\n false,\n 'pinned_at',\n );\n }\n\n /**\n * removePinnedMessage - removes pinned message from pinnedMessages\n *\n * @param {MessageResponse} message message to remove\n *\n */\n removePinnedMessage(message: MessageResponse) {\n const { result } = this.removeMessageFromArray(this.pinnedMessages, message);\n this.pinnedMessages = result;\n }\n\n addReaction(\n reaction: ReactionResponse,\n message?: MessageResponse,\n enforce_unique?: boolean,\n ) {\n const messageWithReaction = message;\n let messageFromState: LocalMessage | undefined;\n if (!messageWithReaction) {\n messageFromState = this.findMessage(reaction.message_id);\n }\n\n if (!messageWithReaction && !messageFromState) {\n return;\n }\n\n const messageToUpdate = messageWithReaction ?? messageFromState;\n const updateData = {\n id: messageToUpdate?.id,\n parent_id: messageToUpdate?.parent_id,\n pinned: messageToUpdate?.pinned,\n show_in_channel: messageToUpdate?.show_in_channel,\n };\n\n this._updateMessage(updateData, (msg) => {\n if (messageWithReaction) {\n const updatedMessage = { ...messageWithReaction };\n // This part will remove own_reactions from what is essentially\n // a copy of event.message; we do not want to return that as someone\n // else reaction would remove our own_reactions needlessly. This\n // only happens when we are not the sender of the reaction. We need\n // the variable itself so that the event can be properly enriched\n // later on.\n messageWithReaction.own_reactions = this._addOwnReactionToMessage(\n msg.own_reactions,\n reaction,\n enforce_unique,\n );\n // Whenever we are the ones sending the reaction, the helper enriches\n // own_reactions as normal so we can use that, otherwise we fallback\n // to whatever state we had.\n updatedMessage.own_reactions =\n this._channel.getClient().userID === reaction.user_id\n ? messageWithReaction.own_reactions\n : msg.own_reactions;\n return this.formatMessage(updatedMessage);\n }\n\n if (messageFromState) {\n return this._addReactionToState(messageFromState, reaction, enforce_unique);\n }\n\n return msg;\n });\n return messageWithReaction ?? messageFromState;\n }\n\n _addReactionToState(\n messageFromState: LocalMessage,\n reaction: ReactionResponse,\n enforce_unique?: boolean,\n ) {\n if (!messageFromState.reaction_groups) {\n messageFromState.reaction_groups = {};\n }\n\n // 1. Firstly, get rid of all of our own reactions from the reaction_groups\n // if enforce_unique is enabled.\n if (enforce_unique) {\n for (const ownReaction of messageFromState.own_reactions ?? []) {\n const oldOwnReactionTypeData = messageFromState.reaction_groups[ownReaction.type];\n messageFromState.reaction_groups[ownReaction.type] = {\n ...oldOwnReactionTypeData,\n count: oldOwnReactionTypeData.count - 1,\n sum_scores: oldOwnReactionTypeData.sum_scores - (ownReaction.score ?? 1),\n };\n // If there are no reactions left in this group, simply remove it.\n if (messageFromState.reaction_groups[ownReaction.type].count < 1) {\n delete messageFromState.reaction_groups[ownReaction.type];\n }\n }\n }\n\n const newReactionGroups = messageFromState.reaction_groups;\n const oldReactionTypeData = newReactionGroups[reaction.type];\n const score = reaction.score ?? 1;\n\n // 2. Next, update the reaction_groups with the new reaction.\n messageFromState.reaction_groups[reaction.type] = oldReactionTypeData\n ? {\n ...oldReactionTypeData,\n count: oldReactionTypeData.count + 1,\n sum_scores: oldReactionTypeData.sum_scores + score,\n last_reaction_at: reaction.created_at,\n }\n : {\n count: 1,\n first_reaction_at: reaction.created_at,\n last_reaction_at: reaction.created_at,\n sum_scores: score,\n };\n\n // 3. Update the own_reactions with the new reaction.\n messageFromState.own_reactions = this._addOwnReactionToMessage(\n messageFromState.own_reactions,\n reaction,\n enforce_unique,\n );\n\n // 4. Finally, update the latest_reactions with the new reaction,\n // while respecting enforce_unique.\n const userId = this._channel.getClient().userID;\n messageFromState.latest_reactions = enforce_unique\n ? [\n ...(messageFromState.latest_reactions || []).filter(\n (r) => r.user_id !== userId,\n ),\n reaction,\n ]\n : [...(messageFromState.latest_reactions || []), reaction];\n\n return messageFromState;\n }\n\n _addOwnReactionToMessage(\n ownReactions: ReactionResponse[] | null | undefined,\n reaction: ReactionResponse,\n enforce_unique?: boolean,\n ) {\n if (enforce_unique) {\n ownReactions = [];\n } else {\n ownReactions = this._removeOwnReactionFromMessage(ownReactions, reaction);\n }\n\n ownReactions = ownReactions || [];\n if (this._channel.getClient().userID === reaction.user_id) {\n ownReactions.push(reaction);\n }\n\n return ownReactions;\n }\n\n _removeOwnReactionFromMessage(\n ownReactions: ReactionResponse[] | null | undefined,\n reaction: ReactionResponse,\n ) {\n if (ownReactions) {\n return ownReactions.filter(\n (item) => item.user_id !== reaction.user_id || item.type !== reaction.type,\n );\n }\n return ownReactions;\n }\n\n removeReaction(reaction: ReactionResponse, message?: MessageResponse) {\n const messageWithRemovedReaction = message;\n let messageFromState: LocalMessage | undefined;\n if (!messageWithRemovedReaction) {\n messageFromState = this.findMessage(reaction.message_id);\n }\n\n if (!messageWithRemovedReaction && !messageFromState) {\n return;\n }\n\n const messageToUpdate = messageWithRemovedReaction ?? messageFromState;\n const updateData = {\n id: messageToUpdate?.id,\n parent_id: messageToUpdate?.parent_id,\n pinned: messageToUpdate?.pinned,\n show_in_channel: messageToUpdate?.show_in_channel,\n };\n this._updateMessage(updateData, (msg) => {\n if (messageWithRemovedReaction) {\n messageWithRemovedReaction.own_reactions = this._removeOwnReactionFromMessage(\n msg.own_reactions,\n reaction,\n );\n return this.formatMessage(messageWithRemovedReaction);\n }\n\n if (messageFromState) {\n return this._removeReactionFromState(messageFromState, reaction);\n }\n\n return msg;\n });\n return messageWithRemovedReaction;\n }\n\n _removeReactionFromState(messageFromState: LocalMessage, reaction: ReactionResponse) {\n const reactionToRemove = messageFromState.own_reactions?.find(\n (r) => r.type === reaction.type,\n );\n if (reactionToRemove && messageFromState.reaction_groups?.[reactionToRemove.type]) {\n const newReactionGroup = messageFromState.reaction_groups[reactionToRemove.type];\n messageFromState.reaction_groups[reactionToRemove.type] = {\n ...newReactionGroup,\n count: newReactionGroup.count - 1,\n sum_scores: newReactionGroup.sum_scores - (reactionToRemove.score ?? 1),\n };\n // If there are no reactions left in this group, simply remove it.\n if (messageFromState.reaction_groups[reactionToRemove.type].count < 1) {\n delete messageFromState.reaction_groups[reactionToRemove.type];\n }\n }\n messageFromState.own_reactions = messageFromState.own_reactions?.filter(\n (r) => r.type !== reaction.type,\n );\n const userId = this._channel.getClient().userID;\n messageFromState.latest_reactions = messageFromState.latest_reactions?.filter(\n (r) => !(r.user_id === userId && r.type === reaction.type),\n );\n return messageFromState;\n }\n\n _updateQuotedMessageReferences({\n message,\n remove,\n }: {\n message: MessageResponse;\n remove?: boolean;\n }) {\n const parseMessage = (m: ReturnType<ChannelState['formatMessage']>) =>\n ({\n ...m,\n created_at: m.created_at.toISOString(),\n pinned_at: m.pinned_at?.toISOString(),\n updated_at: m.updated_at?.toISOString(),\n }) as unknown as MessageResponse;\n\n const update = (messages: LocalMessage[]) => {\n const updatedMessages = messages.reduce<MessageResponse[]>((acc, msg) => {\n if (msg.quoted_message_id === message.id) {\n acc.push({\n ...parseMessage(msg),\n quoted_message: remove ? { ...message, attachments: [] } : message,\n });\n }\n return acc;\n }, []);\n this.addMessagesSorted(updatedMessages, true);\n };\n\n if (!message.parent_id) {\n this.messageSets.forEach((set) => update(set.messages));\n } else if (message.parent_id && this.threads[message.parent_id]) {\n // prevent going through all the threads even though it is possible to quote a message from another thread\n update(this.threads[message.parent_id]);\n }\n }\n\n removeQuotedMessageReferences(message: MessageResponse) {\n this._updateQuotedMessageReferences({ message, remove: true });\n }\n\n /**\n * Updates all instances of given message in channel state\n * @param message\n * @param updateFunc\n */\n _updateMessage(\n message: {\n id?: string;\n parent_id?: string;\n pinned?: boolean;\n show_in_channel?: boolean;\n },\n updateFunc: (\n msg: ReturnType<ChannelState['formatMessage']>,\n ) => ReturnType<ChannelState['formatMessage']>,\n ) {\n const { parent_id, show_in_channel, pinned } = message;\n\n if (parent_id && this.threads[parent_id]) {\n const thread = this.threads[parent_id];\n const msgIndex = thread.findIndex((msg) => msg.id === message.id);\n if (msgIndex !== -1) {\n thread[msgIndex] = updateFunc(thread[msgIndex]);\n this.threads[parent_id] = thread;\n }\n }\n\n if ((!show_in_channel && !parent_id) || show_in_channel) {\n const messageSetIndex = this.findMessageSetIndex(message);\n if (messageSetIndex !== -1) {\n const msgIndex = this.messageSets[messageSetIndex].messages.findIndex(\n (msg) => msg.id === message.id,\n );\n if (msgIndex !== -1) {\n const upMsg = updateFunc(this.messageSets[messageSetIndex].messages[msgIndex]);\n this.messageSets[messageSetIndex].messages[msgIndex] = upMsg;\n }\n }\n }\n\n if (pinned) {\n const msgIndex = this.pinnedMessages.findIndex((msg) => msg.id === message.id);\n if (msgIndex !== -1) {\n this.pinnedMessages[msgIndex] = updateFunc(this.pinnedMessages[msgIndex]);\n }\n }\n }\n\n /**\n * Setter for isUpToDate.\n *\n * @param isUpToDate Flag which indicates if channel state contain latest/recent messages or no.\n * This flag should be managed by UI sdks using a setter - setIsUpToDate.\n * When false, any new message (received by websocket event - message.new) will not\n * be pushed on to message list.\n */\n setIsUpToDate = (isUpToDate: boolean) => {\n this.isUpToDate = isUpToDate;\n };\n\n /**\n * _addToMessageList - Adds a message to a list of messages, tries to update first, appends if message isn't found\n *\n * @param {Array<ReturnType<ChannelState['formatMessage']>>} messages A list of messages\n * @param message\n * @param {boolean} timestampChanged Whether updating a message with changed created_at value.\n * @param {string} sortBy field name to use to sort the messages by\n * @param {boolean} addIfDoesNotExist Add message if it is not in the list, used to prevent out of order updated messages from being added.\n */\n _addToMessageList(\n messages: Array<ReturnType<ChannelState['formatMessage']>>,\n message: ReturnType<ChannelState['formatMessage']>,\n timestampChanged = false,\n sortBy: 'pinned_at' | 'created_at' = 'created_at',\n addIfDoesNotExist = true,\n ) {\n return addToMessageList(\n messages,\n message,\n timestampChanged,\n sortBy,\n addIfDoesNotExist,\n );\n }\n\n /**\n * removeMessage - Description\n *\n * @param {{ id: string; parent_id?: string }} messageToRemove Object of the message to remove. Needs to have at id specified.\n *\n * @return {boolean} Returns if the message was removed\n */\n removeMessage(messageToRemove: {\n id: string;\n messageSetIndex?: number;\n parent_id?: string;\n }) {\n let isRemoved = false;\n if (messageToRemove.parent_id && this.threads[messageToRemove.parent_id]) {\n const { removed, result: threadMessages } = this.removeMessageFromArray(\n this.threads[messageToRemove.parent_id],\n messageToRemove,\n );\n\n this.threads[messageToRemove.parent_id] = threadMessages;\n isRemoved = removed;\n } else {\n const messageSetIndex =\n messageToRemove.messageSetIndex ?? this.findMessageSetIndex(messageToRemove);\n if (messageSetIndex !== -1) {\n const { removed, result: messages } = this.removeMessageFromArray(\n this.messageSets[messageSetIndex].messages,\n messageToRemove,\n );\n this.messageSets[messageSetIndex].messages = messages;\n isRemoved = removed;\n }\n }\n\n return isRemoved;\n }\n\n removeMessageFromArray = (\n msgArray: Array<ReturnType<ChannelState['formatMessage']>>,\n msg: { id: string; parent_id?: string },\n ) => {\n const result = msgArray.filter(\n (message) => !(!!message.id && !!msg.id && message.id === msg.id),\n );\n\n return { removed: result.length < msgArray.length, result };\n };\n\n /**\n * Updates the message.user property with updated user object, for messages.\n *\n * @param {UserResponse} user\n */\n updateUserMessages = (user: UserResponse) => {\n const _updateUserMessages = (\n messages: Array<ReturnType<ChannelState['formatMessage']>>,\n user: UserResponse,\n ) => {\n for (let i = 0; i < messages.length; i++) {\n const m = messages[i];\n if (m.user?.id === user.id) {\n messages[i] = { ...m, user };\n }\n }\n };\n\n this.messageSets.forEach((set) => _updateUserMessages(set.messages, user));\n\n for (const parentId in this.threads) {\n _updateUserMessages(this.threads[parentId], user);\n }\n\n _updateUserMessages(this.pinnedMessages, user);\n };\n\n /**\n * Marks the messages as deleted, from deleted user.\n *\n * @param {UserResponse} user\n * @param {boolean} hardDelete\n */\n deleteUserMessages = (\n user: UserResponse,\n hardDelete = false,\n deletedAt?: LocalMessage['deleted_at'],\n ) => {\n this.messageSets.forEach(({ messages }) =>\n _deleteUserMessages({ messages, user, hardDelete, deletedAt: deletedAt ?? null }),\n );\n\n for (const parentId in this.threads) {\n _deleteUserMessages({\n messages: this.threads[parentId],\n user,\n hardDelete,\n deletedAt: deletedAt ?? null,\n });\n }\n\n _deleteUserMessages({\n messages: this.pinnedMessages,\n user,\n hardDelete,\n deletedAt: deletedAt ?? null,\n });\n };\n\n /**\n * filterErrorMessages - Removes error messages from the channel state.\n *\n */\n filterErrorMessages() {\n const filteredMessages = this.latestMessages.filter(\n (message) => message.type !== 'error',\n );\n\n this.latestMessages = filteredMessages;\n }\n\n /**\n * clean - Remove stale data such as users that stayed in typing state for more than 5 seconds\n */\n clean() {\n const now = new Date();\n // prevent old users from showing up as typing\n for (const [userID, lastEvent] of Object.entries(this.typing)) {\n const receivedAt =\n typeof lastEvent.received_at === 'string'\n ? new Date(lastEvent.received_at)\n : lastEvent.received_at || new Date();\n if (now.getTime() - receivedAt.getTime() > 7000) {\n delete this.typing[userID];\n this._channel.getClient().dispatchEvent({\n cid: this._channel.cid,\n type: 'typing.stop',\n user: { id: userID },\n } as Event);\n }\n }\n }\n\n clearMessages() {\n this.initMessages();\n this.pinnedMessages = [];\n }\n\n initMessages() {\n this.messageSets = [\n {\n messages: [],\n isLatest: true,\n isCurrent: true,\n pagination: DEFAULT_MESSAGE_SET_PAGINATION,\n },\n ];\n }\n\n /**\n * loadMessageIntoState - Loads a given message (and messages around it) into the state\n *\n * @param {string} messageId The id of the message, or 'latest' to indicate switching to the latest messages\n * @param {string} parentMessageId The id of the parent message, if we want load a thread reply\n * @param {number} limit The page size if the message has to be queried from the server\n */\n async loadMessageIntoState(\n messageId: string | 'latest',\n parentMessageId?: string,\n limit = 25,\n ) {\n let messageSetIndex: number;\n let switchedToMessageSet = false;\n let loadedMessageThread = false;\n const messageIdToFind = parentMessageId || messageId;\n if (messageId === 'latest') {\n if (this.messages === this.latestMessages) {\n return;\n }\n messageSetIndex = this.messageSets.findIndex((s) => s.isLatest);\n } else {\n messageSetIndex = this.findMessageSetIndex({ id: messageIdToFind });\n }\n if (messageSetIndex !== -1) {\n this.switchToMessageSet(messageSetIndex);\n switchedToMessageSet = true;\n }\n loadedMessageThread =\n !parentMessageId ||\n !!this.threads[parentMessageId]?.find((m) => m.id === messageId);\n if (switchedToMessageSet && loadedMessageThread) {\n return;\n }\n if (!switchedToMessageSet) {\n await this._channel.query(\n { messages: { id_around: messageIdToFind, limit } },\n 'new',\n );\n }\n if (!loadedMessageThread && parentMessageId) {\n await this._channel.getReplies(parentMessageId, { id_around: messageId, limit });\n }\n messageSetIndex = this.findMessageSetIndex({ id: messageIdToFind });\n if (messageSetIndex !== -1) {\n this.switchToMessageSet(messageSetIndex);\n }\n }\n\n /**\n * findMessage - Finds a message inside the state\n *\n * @param {string} messageId The id of the message\n * @param {string} parentMessageId The id of the parent message, if we want load a thread reply\n *\n * @return {ReturnType<ChannelState['formatMessage']>} Returns the message, or undefined if the message wasn't found\n */\n findMessage(messageId: string, parentMessageId?: string) {\n if (parentMessageId) {\n const messages = this.threads[parentMessageId];\n if (!messages) {\n return undefined;\n }\n return messages.find((m) => m.id === messageId);\n }\n\n const messageSetIndex = this.findMessageSetIndex({ id: messageId });\n if (messageSetIndex === -1) {\n return undefined;\n }\n return this.messageSets[messageSetIndex].messages.find((m) => m.id === messageId);\n }\n\n private switchToMessageSet(index: number) {\n const currentMessages = this.messageSets.find((s) => s.isCurrent);\n if (!currentMessages) {\n return;\n }\n currentMessages.isCurrent = false;\n this.messageSets[index].isCurrent = true;\n }\n\n private areMessageSetsOverlap(\n messages1: Array<{ id: string }>,\n messages2: Array<{ id: string }>,\n ) {\n return messages1.some((m1) => messages2.find((m2) => m1.id === m2.id));\n }\n\n private findMessageSetIndex(message: { id?: string }) {\n return this.messageSets.findIndex(\n (set) => !!set.messages.find((m) => m.id === message.id),\n );\n }\n\n private findTargetMessageSet(\n newMessages: (MessageResponse | LocalMessage)[],\n addIfDoesNotExist = true,\n messageSetToAddToIfDoesNotExist: MessageSetType = 'current',\n ) {\n let messagesToAdd: (MessageResponse | LocalMessage)[] = newMessages;\n let targetMessageSetIndex!: number;\n if (addIfDoesNotExist) {\n const overlappingMessageSetIndices = this.messageSets\n .map((_, i) => i)\n .filter((i) =>\n this.areMessageSetsOverlap(this.messageSets[i].messages, newMessages),\n );\n switch (messageSetToAddToIfDoesNotExist) {\n case 'new':\n if (overlappingMessageSetIndices.length > 0) {\n targetMessageSetIndex = overlappingMessageSetIndices[0];\n // No new message set is created if newMessages only contains thread replies\n } else if (newMessages.some((m) => !m.parent_id)) {\n this.messageSets.push({\n messages: [],\n isCurrent: false,\n isLatest: false,\n pagination: DEFAULT_MESSAGE_SET_PAGINATION,\n });\n targetMessageSetIndex = this.messageSets.length - 1;\n }\n break;\n case 'current':\n targetMessageSetIndex = this.messageSets.findIndex((s) => s.isCurrent);\n break;\n case 'latest':\n targetMessageSetIndex = this.messageSets.findIndex((s) => s.isLatest);\n break;\n default:\n targetMessageSetIndex = -1;\n }\n // when merging the target set will be the first one from the overlapping message sets\n const mergeTargetMessageSetIndex = overlappingMessageSetIndices.splice(0, 1)[0];\n const mergeSourceMessageSetIndices = [...overlappingMessageSetIndices];\n if (\n mergeTargetMessageSetIndex !== undefined &&\n mergeTargetMessageSetIndex !== targetMessageSetIndex\n ) {\n mergeSourceMessageSetIndices.push(targetMessageSetIndex);\n }\n // merge message sets\n if (mergeSourceMessageSetIndices.length > 0) {\n const target = this.messageSets[mergeTargetMessageSetIndex];\n const sources = this.messageSets.filter(\n (_, i) => mergeSourceMessageSetIndices.indexOf(i) !== -1,\n );\n sources.forEach((messageSet) => {\n target.isLatest = target.isLatest || messageSet.isLatest;\n target.isCurrent = target.isCurrent || messageSet.isCurrent;\n target.pagination.hasPrev =\n messageSet.messages[0].created_at < target.messages[0].created_at\n ? messageSet.pagination.hasPrev\n : target.pagination.hasPrev;\n target.pagination.hasNext =\n target.messages.slice(-1)[0].created_at <\n messageSet.messages.slice(-1)[0].created_at\n ? messageSet.pagination.hasNext\n : target.pagination.hasNext;\n messagesToAdd = [...messagesToAdd, ...messageSet.messages];\n });\n sources.forEach((s) => this.messageSets.splice(this.messageSets.indexOf(s), 1));\n const overlappingMessageSetIndex = this.messageSets.findIndex((s) =>\n this.areMessageSetsOverlap(s.messages, newMessages),\n );\n targetMessageSetIndex = overlappingMessageSetIndex;\n }\n } else {\n // assumes that all new messages belong to the same set\n targetMessageSetIndex = this.findMessageSetIndex(newMessages[0]);\n }\n\n return { targetMessageSetIndex, messagesToAdd };\n }\n}\n", "import type { Attachment, SharedLocationResponse } from '../types';\nimport type {\n AudioAttachment,\n FileAttachment,\n ImageAttachment,\n LocalAttachment,\n LocalAudioAttachment,\n LocalFileAttachment,\n LocalImageAttachment,\n LocalUploadAttachment,\n LocalVideoAttachment,\n LocalVoiceRecordingAttachment,\n UploadedAttachment,\n VideoAttachment,\n VoiceRecordingAttachment,\n} from './types';\n\nexport const isScrapedContent = (attachment: Attachment) =>\n !!attachment?.og_scrape_url || !!attachment?.title_link;\n\nexport const isLocalAttachment = (attachment: unknown): attachment is LocalAttachment =>\n !!(attachment as LocalAttachment)?.localMetadata?.id;\n\nexport const isLocalUploadAttachment = (\n attachment: unknown,\n): attachment is LocalUploadAttachment =>\n !!(attachment as LocalAttachment)?.localMetadata?.uploadState;\n\nexport const isFileAttachment = (\n attachment: Attachment | LocalAttachment,\n supportedVideoFormat: string[] = [],\n): attachment is FileAttachment =>\n attachment.type === 'file' ||\n !!(\n attachment.mime_type &&\n supportedVideoFormat.indexOf(attachment.mime_type) === -1 &&\n attachment.type !== 'video'\n );\n\nexport const isLocalFileAttachment = (\n attachment: Attachment | LocalAttachment,\n): attachment is LocalFileAttachment =>\n isFileAttachment(attachment) && isLocalAttachment(attachment);\n\nexport const isImageAttachment = (\n attachment: Attachment,\n): attachment is ImageAttachment =>\n attachment.type === 'image' && !isScrapedContent(attachment);\n\nexport const isLocalImageAttachment = (\n attachment: Attachment | LocalAttachment,\n): attachment is LocalImageAttachment =>\n isImageAttachment(attachment) && isLocalAttachment(attachment);\n\nexport const isAudioAttachment = (\n attachment: Attachment | LocalAttachment,\n): attachment is AudioAttachment => attachment.type === 'audio';\n\nexport const isLocalAudioAttachment = (\n attachment: Attachment | LocalAttachment,\n): attachment is LocalAudioAttachment =>\n isAudioAttachment(attachment) && isLocalAttachment(attachment);\n\nexport const isVoiceRecordingAttachment = (\n attachment: Attachment | LocalAttachment,\n): attachment is VoiceRecordingAttachment => attachment.type === 'voiceRecording';\n\nexport const isLocalVoiceRecordingAttachment = (\n attachment: Attachment | LocalAttachment,\n): attachment is LocalVoiceRecordingAttachment =>\n isVoiceRecordingAttachment(attachment) && isLocalAttachment(attachment);\n\nexport const isVideoAttachment = (\n attachment: Attachment | LocalAttachment,\n supportedVideoFormat: string[] = [],\n): attachment is VideoAttachment =>\n attachment.type === 'video' ||\n !!(attachment.mime_type && supportedVideoFormat.indexOf(attachment.mime_type) !== -1);\n\nexport const isLocalVideoAttachment = (\n attachment: Attachment | LocalAttachment,\n): attachment is LocalVideoAttachment =>\n isVideoAttachment(attachment) && isLocalAttachment(attachment);\n\nexport const isUploadedAttachment = (\n attachment: Attachment,\n): attachment is UploadedAttachment =>\n isAudioAttachment(attachment) ||\n isFileAttachment(attachment) ||\n isImageAttachment(attachment) ||\n isVideoAttachment(attachment) ||\n isVoiceRecordingAttachment(attachment);\n\nexport const isSharedLocationResponse = (\n location: unknown,\n): location is SharedLocationResponse =>\n !!(location as SharedLocationResponse).latitude &&\n !!(location as SharedLocationResponse).longitude &&\n !!(location as SharedLocationResponse).channel_cid;\n", "import type { Attachment } from '../types';\nimport { generateUUIDv4 } from '../utils';\nimport { isLocalAttachment } from './attachmentIdentity';\nimport type {\n BaseLocalAttachmentMetadata,\n FileLike,\n FileReference,\n LocalAttachment,\n} from './types';\n\nexport const isFile = (fileLike: FileReference | File | Blob): fileLike is File =>\n !!(fileLike as File).lastModified && !('uri' in fileLike);\n\nexport const isFileList = (obj: unknown): obj is FileList => {\n if (obj === null || obj === undefined) return false;\n if (typeof obj !== 'object') return false;\n\n return (\n (typeof FileList !== 'undefined' && (obj as object) instanceof FileList) ||\n ('item' in obj && 'length' in obj && !Array.isArray(obj))\n );\n};\n\nexport const isBlobButNotFile = (obj: unknown): obj is Blob =>\n obj instanceof Blob && !(obj instanceof File);\n\nexport const isFileReference = (obj: FileReference | FileLike): obj is FileReference =>\n obj !== null &&\n typeof obj === 'object' &&\n !isFile(obj) &&\n !isBlobButNotFile(obj) &&\n typeof obj.name === 'string' &&\n typeof obj.uri === 'string' &&\n typeof obj.size === 'number' &&\n typeof obj.type === 'string';\n\nexport const createFileFromBlobs = ({\n blobsArray,\n fileName,\n mimeType,\n}: {\n blobsArray: Blob[];\n fileName: string;\n mimeType: string;\n}) => {\n const concatenatedBlob = new Blob(blobsArray, { type: mimeType });\n return new File([concatenatedBlob], fileName, { type: concatenatedBlob.type });\n};\n\nexport const getExtensionFromMimeType = (mimeType: string) => {\n const match = mimeType.match(/\\/([^/;]+)/);\n return match?.[1];\n};\n\nexport const readFileAsArrayBuffer = (file: File): Promise<ArrayBuffer> =>\n new Promise((resolve, reject) => {\n const fileReader = new FileReader();\n fileReader.onload = () => {\n resolve(fileReader.result as ArrayBuffer);\n };\n\n fileReader.onerror = () => {\n reject(fileReader.error);\n };\n\n fileReader.readAsArrayBuffer(file);\n });\n\nexport const generateFileName = (mimeType: string) => {\n const extension = getExtensionFromMimeType(mimeType);\n return `file_${new Date().toISOString()}${extension ? '.' + extension : ''}`;\n};\n\nexport const isImageFile = (fileLike: FileReference | FileLike) => {\n const mimeType = fileLike.type;\n return mimeType.startsWith('image/') && !mimeType.endsWith('.photoshop'); // photoshop files begin with 'image/'\n};\n\nexport const getAttachmentTypeFromMimeType = (mimeType: string) => {\n if (mimeType.startsWith('image/') && !mimeType.endsWith('.photoshop')) return 'image';\n if (mimeType.includes('video/')) return 'video';\n if (mimeType.includes('audio/')) return 'audio';\n return 'file';\n};\n\nexport const ensureIsLocalAttachment = (\n attachment: Attachment | LocalAttachment,\n): LocalAttachment | null => {\n if (!attachment) return null;\n if (isLocalAttachment(attachment)) {\n return attachment;\n }\n // local is considered local only if localMetadata has `id` so this is to doublecheck\n const { localMetadata, ...rest } = attachment as LocalAttachment;\n return {\n localMetadata: {\n ...(localMetadata ?? {}),\n id: (localMetadata as BaseLocalAttachmentMetadata)?.id || generateUUIDv4(),\n },\n ...rest,\n };\n};\n", "import type { MiddlewareHandlerParams } from '../../../../middleware';\nimport type {\n AttachmentPostUploadMiddleware,\n AttachmentPostUploadMiddlewareState,\n} from '../types';\nimport { isLocalImageAttachment } from '../../../attachmentIdentity';\nimport type { LocalNotImageAttachment } from '../../../types';\n\nexport const createPostUploadAttachmentEnrichmentMiddleware =\n (): AttachmentPostUploadMiddleware => ({\n id: 'stream-io/attachment-manager-middleware/post-upload-enrichment',\n handlers: {\n postProcess: ({\n state,\n discard,\n forward,\n next,\n }: MiddlewareHandlerParams<AttachmentPostUploadMiddlewareState>) => {\n const { attachment, error, response } = state;\n if (error) return forward();\n if (!attachment || !response) return discard();\n\n const enrichedAttachment = { ...attachment };\n if (isLocalImageAttachment(attachment)) {\n if (attachment.localMetadata.previewUri) {\n URL.revokeObjectURL(attachment.localMetadata.previewUri);\n delete enrichedAttachment.localMetadata.previewUri;\n }\n enrichedAttachment.image_url = response.file;\n } else {\n (enrichedAttachment as LocalNotImageAttachment).asset_url = response.file;\n }\n if (response.thumb_url) {\n (enrichedAttachment as LocalNotImageAttachment).thumb_url = response.thumb_url;\n }\n\n return next({\n ...state,\n attachment: enrichedAttachment,\n });\n },\n },\n });\n", "interface PendingPromise {\n onContinued: () => void;\n promise: Promise<unknown>;\n}\n\ntype AsyncWrapper<P extends unknown[], T> = (\n tag: string | symbol,\n cb: (...args: P) => Promise<T>,\n) => {\n cb: () => Promise<T>;\n onContinued: () => void;\n};\n\n/**\n * Runs async functions serially. Useful for wrapping async actions that\n * should never run simultaneously: if marked with the same tag, functions\n * will run one after another.\n *\n * @param tag Async functions with the same tag will run serially. Async functions\n * with different tags can run in parallel.\n * @param cb Async function to run.\n * @returns Promise that resolves when async functions returns.\n */\nexport const withoutConcurrency = createRunner(wrapWithContinuationTracking);\n\n/**\n * Runs async functions serially, and cancels all other actions with the same tag\n * when a new action is scheduled. Useful for wrapping async actions that override\n * each other (e.g. enabling and disabling camera).\n *\n * If an async function hasn't started yet and was canceled, it will never run.\n * If an async function is already running and was canceled, it will be notified\n * via an abort signal passed as an argument.\n *\n * @param tag Async functions with the same tag will run serially and are canceled\n * when a new action with the same tag is scheduled.\n * @param cb Async function to run. Receives AbortSignal as the only argument.\n * @returns Promise that resolves when async functions returns. If the function didn't\n * start and was canceled, will resolve with 'canceled'. If the function started to run,\n * it's up to the function to decide how to react to cancelation.\n */\nexport const withCancellation = createRunner(wrapWithCancellation);\n\nconst pendingPromises = new Map<string | symbol, PendingPromise>();\n\nexport function hasPending(tag: string | symbol) {\n return pendingPromises.has(tag);\n}\n\nexport async function settled(tag: string | symbol) {\n await pendingPromises.get(tag)?.promise;\n}\n\n/**\n * Implements common functionality of running async functions serially, by chaining\n * their promises one after another.\n *\n * Before running, async function is \"wrapped\" using the provided wrapper. This wrapper\n * can add additional steps to run before or after the function.\n *\n * When async function is scheduled to run, the previous function is notified\n * by calling the associated onContinued callback. This behavior of this callback\n * is defined by the wrapper.\n */\nfunction createRunner<P extends unknown[], T>(wrapper: AsyncWrapper<P, T>) {\n return function run(tag: string | symbol, cb: (...args: P) => Promise<T>) {\n const { cb: wrapped, onContinued } = wrapper(tag, cb);\n const pending = pendingPromises.get(tag);\n pending?.onContinued();\n const promise = pending ? pending.promise.then(wrapped, wrapped) : wrapped();\n pendingPromises.set(tag, { promise, onContinued });\n return promise;\n };\n}\n\n/**\n * Wraps an async function with an additional step run after the function:\n * if the function is the last in the queue, it cleans up the whole chain\n * of promises after finishing.\n */\nfunction wrapWithContinuationTracking<T>(tag: string | symbol, cb: () => Promise<T>) {\n let hasContinuation = false;\n const wrapped = () =>\n cb().finally(() => {\n if (!hasContinuation) {\n pendingPromises.delete(tag);\n }\n });\n const onContinued = () => (hasContinuation = true);\n return { cb: wrapped, onContinued };\n}\n\n/**\n * Wraps an async function with additional functionality:\n * 1. Associates an abort signal with every function, that is passed to it\n * as an argument. When a new function is scheduled to run after the current\n * one, current signal is aborted.\n * 2. If current function didn't start and was aborted, in will never start.\n * 3. If the function is the last in the queue, it cleans up the whole chain\n * of promises after finishing.\n *\n * The cb is passed the AbortController instance for a given execution.\n * The cb should implement own cancellation logic to reflect that the given AbortController has been aborted.\n *\n * ```\n * const cb = async (signal: AbortSignal) => {\n * await new Promise(resolve => setTimeout(resolve, 50));\n * if (signal.aborted) {\n * abortedSignals.push(signal);\n * return 'canceled';\n * }\n * return 1;\n * };\n * const result = withCancellation('tag-x', cb); // the result variable may acquire value \"canceled\" or 1\n * ```\n */\nfunction wrapWithCancellation<T>(\n tag: string | symbol,\n cb: (signal: AbortSignal) => Promise<T | 'canceled'>,\n) {\n const ac = new AbortController();\n const wrapped = () => {\n if (ac.signal.aborted) {\n return Promise.resolve('canceled' as const);\n }\n\n return cb(ac.signal).finally(() => {\n if (!ac.signal.aborted) {\n pendingPromises.delete(tag);\n }\n });\n };\n const onContinued = () => ac.abort();\n return { cb: wrapped, onContinued };\n}\n", "import { withCancellation } from './utils/concurrency';\nimport { generateUUIDv4 } from './utils';\n\nexport type InsertPosition =\n | {\n after: string;\n before?: never;\n }\n | {\n after?: never;\n before: string;\n };\n\nexport type MiddlewareStatus = 'complete' | 'discard';\n\nexport type MiddlewareExecutionResult<TValue> = {\n state: TValue;\n status?: MiddlewareStatus;\n};\n\nexport type ExecuteParams<TValue> = {\n eventName: string;\n initialValue: TValue;\n /*\n Determines how the concurrently run middleware handlers will be executed:\n - async - all handlers are executed even though the same handler is invoked more than once\n - cancelable - previously invoked handlers of the same eventName that have not yet resolved are canceled\n */\n mode?: 'concurrent' | 'cancelable'; // default 'cancelable'\n};\n\nexport type MiddlewareHandlerParams<TValue> = {\n state: TValue;\n next: (state: TValue) => Promise<MiddlewareExecutionResult<TValue>>;\n complete: (state: TValue) => Promise<MiddlewareExecutionResult<TValue>>;\n discard: () => Promise<MiddlewareExecutionResult<TValue>>;\n forward: () => Promise<MiddlewareExecutionResult<TValue>>;\n};\n\nexport type MiddlewareHandler<TValue> = (\n params: MiddlewareHandlerParams<TValue>,\n) => Promise<MiddlewareExecutionResult<TValue>>;\n\nexport type MiddlewareHandlers<TValue, THandlers extends string> = {\n [K in THandlers]: MiddlewareHandler<TValue>;\n};\n\nexport type Middleware<TValue, THandlers extends string> = {\n id: string;\n handlers: MiddlewareHandlers<TValue, THandlers>;\n};\n\nexport class MiddlewareExecutor<TValue, THandlers extends string> {\n readonly id: string;\n private middleware: Middleware<TValue, THandlers>[] = [];\n\n constructor() {\n this.id = generateUUIDv4();\n }\n\n use(middleware: Middleware<TValue, THandlers> | Middleware<TValue, THandlers>[]) {\n this.middleware = this.middleware.concat(middleware);\n return this;\n }\n\n // todo: document how to re-arrange the order of middleware using replace\n replace(middleware: Middleware<TValue, THandlers>[]) {\n const newMiddleware = [...this.middleware];\n middleware.forEach((upserted) => {\n const existingIndex = this.middleware.findIndex(\n (existing) => existing.id === upserted.id,\n );\n if (existingIndex >= 0) {\n newMiddleware.splice(existingIndex, 1, upserted);\n } else {\n newMiddleware.push(upserted);\n }\n });\n this.middleware = newMiddleware;\n return this;\n }\n\n insert({\n middleware,\n position,\n unique,\n }: {\n middleware: Middleware<TValue, THandlers>[];\n position: InsertPosition;\n unique?: boolean;\n }) {\n if (unique) {\n middleware.forEach((md) => {\n const existingMiddlewareIndex = this.middleware.findIndex((m) => m.id === md.id);\n if (existingMiddlewareIndex >= 0) {\n this.middleware.splice(existingMiddlewareIndex, 1);\n }\n });\n }\n const targetId = position.after || position.before;\n const targetIndex = this.middleware.findIndex((m) => m.id === targetId);\n const insertionIndex = position.after ? targetIndex + 1 : targetIndex;\n this.middleware.splice(insertionIndex, 0, ...middleware);\n return this;\n }\n\n setOrder(order: string[]) {\n this.middleware = order\n .map((id) => this.middleware.find((middleware) => middleware.id === id))\n .filter(Boolean) as Middleware<TValue, THandlers>[];\n }\n\n remove(middlewareIds: string | string[]) {\n if (!middlewareIds && !middlewareIds.length) return;\n this.middleware = this.middleware.filter((md) =>\n typeof middlewareIds === 'string'\n ? middlewareIds !== md.id\n : !middlewareIds.includes(md.id),\n );\n }\n\n protected async executeMiddlewareChain({\n eventName,\n initialValue,\n mode = 'cancelable',\n }: ExecuteParams<TValue>): Promise<MiddlewareExecutionResult<TValue>> {\n let index = -1;\n\n const execute = async (\n i: number,\n state: TValue,\n status?: MiddlewareStatus,\n ): Promise<MiddlewareExecutionResult<TValue>> => {\n if (i <= index) {\n throw new Error('next() called multiple times');\n }\n\n index = i;\n\n const returnFromChain =\n i === this.middleware.length ||\n (status && ['complete', 'discard'].includes(status));\n if (returnFromChain) return { state, status };\n\n const middleware = this.middleware[i];\n const handler = middleware.handlers[eventName as THandlers];\n\n if (!handler) {\n return execute(i + 1, state, status);\n }\n\n const next = (adjustedState: TValue) => execute(i + 1, adjustedState);\n const complete = (adjustedState: TValue) =>\n execute(i + 1, adjustedState, 'complete');\n const discard = () => execute(i + 1, state, 'discard');\n const forward = () => execute(i + 1, state);\n\n return await handler({\n state,\n next,\n complete,\n discard,\n forward,\n });\n };\n\n const result =\n mode === 'cancelable'\n ? await withCancellation(\n `middleware-execution-${this.id}-${eventName}`,\n async (abortSignal) => {\n const result = await execute(0, initialValue);\n if (abortSignal.aborted) {\n return 'canceled';\n }\n return result;\n },\n )\n : await execute(0, initialValue);\n\n return result === 'canceled' ? { state: initialValue, status: 'discard' } : result;\n }\n\n async execute({\n eventName,\n initialValue: initialState,\n mode,\n }: ExecuteParams<TValue>): Promise<MiddlewareExecutionResult<TValue>> {\n return await this.executeMiddlewareChain({\n eventName,\n initialValue: initialState,\n mode,\n });\n }\n}\n", "import type { MiddlewareHandlerParams } from '../../../../middleware';\nimport type { MessageComposer } from '../../../messageComposer';\nimport type {\n AttachmentPostUploadMiddleware,\n AttachmentPostUploadMiddlewareState,\n} from '../types';\n\nexport const createUploadErrorHandlerMiddleware = (\n composer: MessageComposer,\n): AttachmentPostUploadMiddleware => ({\n id: 'stream-io/attachment-manager-middleware/upload-error',\n handlers: {\n postProcess: ({\n state,\n discard,\n forward,\n }: MiddlewareHandlerParams<AttachmentPostUploadMiddlewareState>) => {\n const { attachment, error } = state;\n if (!error) return forward();\n if (!attachment) return discard();\n\n const reason = error instanceof Error ? error.message : 'unknown error';\n composer.client.notifications.addError({\n message: 'Error uploading attachment',\n origin: {\n emitter: 'AttachmentManager',\n context: { attachment },\n },\n options: {\n type: 'api:attachment:upload:failed',\n metadata: { reason },\n originalError: error,\n },\n });\n\n return forward();\n },\n },\n});\n", "import { MiddlewareExecutor } from '../../../../middleware';\nimport type {\n AttachmentPostUploadMiddlewareExecutorOptions,\n AttachmentPostUploadMiddlewareState,\n} from '../types';\nimport { createPostUploadAttachmentEnrichmentMiddleware } from './attachmentEnrichment';\nimport { createUploadErrorHandlerMiddleware } from './uploadErrorHandler';\n\nexport class AttachmentPostUploadMiddlewareExecutor extends MiddlewareExecutor<\n AttachmentPostUploadMiddlewareState,\n 'postProcess'\n> {\n constructor({ composer }: AttachmentPostUploadMiddlewareExecutorOptions) {\n super();\n this.use([\n createUploadErrorHandlerMiddleware(composer),\n createPostUploadAttachmentEnrichmentMiddleware(),\n ]);\n }\n}\n", "import type { MiddlewareHandlerParams } from '../../../../middleware';\nimport type { MessageComposer } from '../../../messageComposer';\nimport type {\n AttachmentPreUploadMiddleware,\n AttachmentPreUploadMiddlewareState,\n} from '../types';\nimport type { LocalUploadAttachment } from '../../../types';\n\nexport const createUploadConfigCheckMiddleware = (\n composer: MessageComposer,\n): AttachmentPreUploadMiddleware => ({\n id: 'stream-io/attachment-manager-middleware/file-upload-config-check',\n handlers: {\n prepare: async ({\n state,\n next,\n discard,\n }: MiddlewareHandlerParams<AttachmentPreUploadMiddlewareState>) => {\n const { attachmentManager } = composer;\n if (!attachmentManager || !state.attachment) return discard();\n const uploadPermissionCheck = await attachmentManager.getUploadConfigCheck(\n state.attachment.localMetadata.file,\n );\n\n const attachment: LocalUploadAttachment = {\n ...state.attachment,\n localMetadata: {\n ...state.attachment.localMetadata,\n uploadPermissionCheck,\n uploadState: uploadPermissionCheck.uploadBlocked ? 'blocked' : 'pending',\n },\n };\n\n return next({\n ...state,\n attachment,\n });\n },\n },\n});\n", "import type { MiddlewareHandlerParams } from '../../../../middleware';\nimport type { MessageComposer } from '../../../messageComposer';\nimport type {\n AttachmentPreUploadMiddleware,\n AttachmentPreUploadMiddlewareState,\n} from '../types';\n\nexport const createBlockedAttachmentUploadNotificationMiddleware = (\n composer: MessageComposer,\n): AttachmentPreUploadMiddleware => ({\n id: 'stream-io/attachment-manager-middleware/blocked-upload-notification',\n handlers: {\n prepare: ({\n state: { attachment },\n forward,\n }: MiddlewareHandlerParams<AttachmentPreUploadMiddlewareState>) => {\n if (!attachment) return forward();\n\n if (attachment.localMetadata.uploadPermissionCheck?.uploadBlocked) {\n composer.client.notifications.addError({\n message: `The attachment upload was blocked`,\n origin: {\n emitter: 'AttachmentManager',\n context: { blockedAttachment: attachment },\n },\n options: {\n type: 'validation:attachment:upload:blocked',\n metadata: {\n reason: attachment.localMetadata.uploadPermissionCheck?.reason,\n },\n },\n });\n }\n\n return forward();\n },\n },\n});\n", "import { MiddlewareExecutor } from '../../../../middleware';\nimport type {\n AttachmentPreUploadMiddlewareExecutorOptions,\n AttachmentPreUploadMiddlewareState,\n} from '../types';\nimport { createUploadConfigCheckMiddleware } from './serverUploadConfigCheck';\nimport { createBlockedAttachmentUploadNotificationMiddleware } from './blockedUploadNotification';\n\nexport class AttachmentPreUploadMiddlewareExecutor extends MiddlewareExecutor<\n AttachmentPreUploadMiddlewareState,\n 'prepare'\n> {\n constructor({ composer }: AttachmentPreUploadMiddlewareExecutorOptions) {\n super();\n this.use([\n createUploadConfigCheckMiddleware(composer),\n createBlockedAttachmentUploadNotificationMiddleware(composer),\n ]);\n }\n}\n", "export type Patch<T> = (value: T) => T;\nexport type ValueOrPatch<T> = T | Patch<T>;\nexport type Handler<T> = (nextValue: T, previousValue: T | undefined) => void;\nexport type Unsubscribe = () => void;\n// aliases\nexport type RemovePreprocessor = Unsubscribe;\nexport type Preprocessor<T> = Handler<T>;\n\nexport const isPatch = <T>(value: ValueOrPatch<T>): value is Patch<T> =>\n typeof value === 'function';\n\n// eslint-disable-next-line @typescript-eslint/no-empty-function\nconst noop = () => {};\n\nexport class StateStore<T extends Record<string, unknown>> {\n protected handlers = new Set<Handler<T>>();\n protected preprocessors = new Set<Preprocessor<T>>();\n\n constructor(protected value: T) {}\n\n /**\n * Allows merging two stores only if their keys differ otherwise there's no way to ensure the data type stability.\n * @experimental\n * This method is experimental and may change in future versions.\n */\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n public merge<Q extends StateStore<any>>(\n stateStore: Q extends StateStore<infer L>\n ? Extract<keyof T, keyof L> extends never\n ? Q\n : never\n : never,\n ) {\n return new MergedStateStore<T, Q extends StateStore<infer L> ? L : never>({\n original: this,\n merged: stateStore,\n });\n }\n\n public next(newValueOrPatch: ValueOrPatch<T>): void {\n // newValue (or patch output) should never be a mutated previous value\n const newValue = isPatch(newValueOrPatch)\n ? newValueOrPatch(this.value)\n : newValueOrPatch;\n\n // do not notify subscribers if the value hasn't changed\n if (newValue === this.value) return;\n\n this.preprocessors.forEach((preprocessor) => preprocessor(newValue, this.value));\n\n const oldValue = this.value;\n this.value = newValue;\n\n this.handlers.forEach((handler) => handler(this.value, oldValue));\n }\n\n public partialNext = (partial: Partial<T>): void =>\n this.next((current) => ({ ...current, ...partial }));\n\n public getLatestValue(): T {\n return this.value;\n }\n\n public subscribe(handler: Handler<T>): Unsubscribe {\n handler(this.value, undefined);\n this.handlers.add(handler);\n return () => {\n this.handlers.delete(handler);\n };\n }\n\n public subscribeWithSelector = <\n O extends Readonly<Record<string, unknown>> | Readonly<unknown[]>,\n >(\n selector: (nextValue: T) => O,\n handler: Handler<O>,\n ) => {\n // begin with undefined to reduce amount of selector calls\n let previouslySelectedValues: O | undefined;\n\n const wrappedHandler: Handler<T> = (nextValue) => {\n const newlySelectedValues = selector(nextValue);\n\n let hasUpdatedValues = typeof previouslySelectedValues === 'undefined';\n\n for (const key in previouslySelectedValues) {\n if (previouslySelectedValues[key] === newlySelectedValues[key]) continue;\n hasUpdatedValues = true;\n break;\n }\n\n if (!hasUpdatedValues) return;\n\n // save a copy of previouslySelectedValues before running\n // handler - if previouslySelectedValues are set to\n // newlySelectedValues after the handler call, there's a chance\n // that it'll never get set as handler can throw and flow might\n // go out of sync\n const previouslySelectedValuesCopy = previouslySelectedValues;\n previouslySelectedValues = newlySelectedValues;\n\n handler(newlySelectedValues, previouslySelectedValuesCopy);\n };\n\n return this.subscribe(wrappedHandler);\n };\n\n /**\n * Registers a preprocessor function that will be called before the state is updated.\n *\n * Preprocessors are invoked with the new and previous values whenever `next` or `partialNext` methods\n * are called, allowing you to mutate or react to the new value before it is set. Preprocessors run in the\n * order they were registered.\n *\n * @example\n * ```ts\n * const store = new StateStore<{ count: number; isMaxValue: bool; }>({ count: 0, isMaxValue: false });\n *\n * store.addPreprocessor((nextValue, prevValue) => {\n * if (nextValue.count > 10) {\n * nextValue.count = 10; // Clamp the value to a maximum of 10\n * }\n *\n * if (nextValue.count === 10) {\n * nextValue.isMaxValue = true; // Set isMaxValue to true if count is 10\n * } else {\n * nextValue.isMaxValue = false; // Reset isMaxValue otherwise\n * }\n * });\n *\n * store.partialNext({ count: 15 });\n *\n * store.getLatestValue(); // { count: 10, isMaxValue: true }\n *\n * store.partialNext({ count: 5 });\n *\n * store.getLatestValue(); // { count: 5, isMaxValue: false }\n * ```\n *\n * @param preprocessor - The function to be called with the next and previous values before the state is updated.\n * @returns A `RemovePreprocessor` function that removes the preprocessor when called.\n */\n public addPreprocessor(preprocessor: Preprocessor<T>): RemovePreprocessor {\n this.preprocessors.add(preprocessor);\n\n return () => {\n this.preprocessors.delete(preprocessor);\n };\n }\n}\n\n/**\n * Represents a merged state store that combines two separate state stores into one.\n *\n * The MergedStateStore allows combining two stores with non-overlapping keys.\n * It extends StateStore with the combined type of both source stores.\n * Changes to either the original or merged store will propagate to the combined store.\n *\n * Note: Direct mutations (next, partialNext, addPreprocessor) are disabled on the merged store.\n * You should instead call these methods on the original or merged stores.\n *\n * @template O The type of the original state store\n * @template M The type of the merged state store\n *\n * @experimental\n * This class is experimental and may change in future versions.\n */\nexport class MergedStateStore<\n O extends Record<string, unknown>,\n M extends Record<string, unknown>,\n> extends StateStore<O & M> {\n public readonly original: StateStore<O>;\n public readonly merged: StateStore<M>;\n private cachedOriginalValue: O;\n private cachedMergedValue: M;\n\n constructor({ original, merged }: { original: StateStore<O>; merged: StateStore<M> }) {\n const originalValue = original.getLatestValue();\n const mergedValue = merged.getLatestValue();\n\n super({\n ...originalValue,\n ...mergedValue,\n });\n\n this.cachedOriginalValue = originalValue;\n this.cachedMergedValue = mergedValue;\n\n this.original = original;\n this.merged = merged;\n }\n\n /**\n * Subscribes to changes in the merged state store.\n *\n * This method extends the base subscribe functionality to handle the merged nature of this store:\n * 1. The first subscriber triggers registration of helper subscribers that listen to both source stores\n * 2. Changes from either source store are propagated to this merged store\n * 3. Source store values are cached to prevent unnecessary updates\n *\n * When the first subscriber is added, the method sets up listeners on both original and merged stores.\n * These listeners update the combined store value whenever either source store changes.\n * All subscriptions (helpers and the actual handler) are tracked so they can be properly cleaned up.\n *\n * @param handler - The callback function that will be executed when the state changes\n * @returns An unsubscribe function that, when called, removes the subscription and any helper subscriptions\n */\n public subscribe(handler: Handler<O & M>) {\n const unsubscribeFunctions: Unsubscribe[] = [];\n\n // first subscriber will also register helpers which listen to changes of the\n // \"original\" and \"merged\" stores, combined outputs will be emitted through super.next\n // whenever cached values do not equal (always apart from the initial subscription)\n // since the actual handler subscription is registered after helpers, the actual\n // handler will run only once\n if (!this.handlers.size) {\n const base = (nextValue: O | M) => {\n super.next((currentValue) => ({\n ...currentValue,\n ...nextValue,\n }));\n };\n\n unsubscribeFunctions.push(\n this.original.subscribe((nextValue) => {\n if (nextValue === this.cachedOriginalValue) return;\n this.cachedOriginalValue = nextValue;\n base(nextValue);\n }),\n this.merged.subscribe((nextValue) => {\n if (nextValue === this.cachedMergedValue) return;\n this.cachedMergedValue = nextValue;\n base(nextValue);\n }),\n );\n }\n\n unsubscribeFunctions.push(super.subscribe(handler));\n\n return () => {\n unsubscribeFunctions.forEach((unsubscribe) => unsubscribe());\n };\n }\n\n /**\n * Retrieves the latest combined state from both original and merged stores.\n *\n * This method extends the base getLatestValue functionality to ensure the merged store\n * remains in sync with its source stores even when there are no active subscribers.\n *\n * When there are no handlers registered, the method:\n * 1. Fetches the latest values from both source stores\n * 2. Compares them with the cached values to detect changes\n * 3. If changes are detected, updates the internal value and caches\n * the new source values to maintain consistency\n *\n * This approach ensures that calling getLatestValue() always returns the most\n * up-to-date combined state, even if the merged store hasn't been actively\n * receiving updates through subscriptions.\n *\n * @returns The latest combined state from both original and merged stores\n */\n public getLatestValue() {\n // if there are no handlers registered to MergedStore then the local value might be out-of-sync\n // pull latest and compare against cached - if they differ, cache latest and produce new combined\n if (!this.handlers.size) {\n const originalValue = this.original.getLatestValue();\n const mergedValue = this.merged.getLatestValue();\n\n if (\n originalValue !== this.cachedOriginalValue ||\n mergedValue !== this.cachedMergedValue\n ) {\n this.value = {\n ...originalValue,\n ...mergedValue,\n };\n this.cachedMergedValue = mergedValue;\n this.cachedOriginalValue = originalValue;\n }\n }\n\n return super.getLatestValue();\n }\n\n // override original methods and \"disable\" them\n public next = () => {\n console.warn(\n `${MergedStateStore.name}.next is disabled, call original.next or merged.next instead`,\n );\n };\n public partialNext = () => {\n console.warn(\n `${MergedStateStore.name}.partialNext is disabled, call original.partialNext or merged.partialNext instead`,\n );\n };\n public addPreprocessor() {\n console.warn(\n `${MergedStateStore.name}.addPreprocessor is disabled, call original.addPreprocessor or merged.addPreprocessor instead`,\n );\n return noop;\n }\n}\n", "/**\n * Core utility functions and types for mergeWith functionality.\n * This file contains shared logic used by both mergeWith and mergeWithDiff functions.\n */\n\nexport type MergeWithCustomizer<T extends object> = (\n objValue: unknown,\n srcValue: unknown,\n key: string | symbol,\n object: T,\n source: object,\n stack: Set<unknown>,\n) => unknown | undefined;\n\nexport type PendingMerge = {\n sourceKey: string | symbol;\n parentTarget: object;\n source: object;\n target: object;\n};\n\nexport type ChangeType = 'added' | 'updated' | 'circular' | (string & {});\n\nexport interface DiffNode {\n type?: ChangeType;\n children: Record<string | symbol, DiffNode>;\n value?: unknown;\n oldValue?: unknown;\n}\n\nexport const isClassInstance = (value: unknown): boolean => {\n if (!value || typeof value !== 'object') return false;\n\n // Arrays are not class instances\n if (Array.isArray(value)) return false;\n\n // Get the prototype chain\n const proto = Object.getPrototypeOf(value);\n\n // If it's null or Object.prototype, it's a plain object\n if (proto === null || proto === Object.prototype) return false;\n\n // Check if it has a constructor that's not Object\n return value.constructor && value.constructor !== Object;\n};\n\n/**\n * Performs a deep comparison between two values to determine if they are equivalent.\n * This is similar to Lodash's isEqual implementation but simplified.\n */\nexport const isEqual = (\n value1: unknown,\n value2: unknown,\n compareStack = new Set<[unknown, unknown]>(),\n objectStack1 = new WeakSet<object>(),\n objectStack2 = new WeakSet<object>(),\n): boolean => {\n // Handle simple equality cases first\n if (value1 === value2) return true;\n\n // If either is null/undefined, they're not equal (already checked ===)\n if (value1 == null || value2 == null) return false;\n\n // Get the type of both values\n const type1 = typeof value1;\n const type2 = typeof value2;\n\n // Different types mean they're not equal\n if (type1 !== type2) return false;\n\n // Handle non-object types that need special comparison\n if (type1 !== 'object') {\n // Special case for NaN\n // eslint-disable-next-line no-self-compare\n if (value1 !== value1 && value2 !== value2) return true;\n return value1 === value2;\n }\n\n // At this point, both values are objects\n const obj1 = value1 as object;\n const obj2 = value2 as object;\n\n // Check for circular references in each object\n if (objectStack1.has(obj1) || objectStack2.has(obj2)) {\n // If either object has been seen before, consider them equal\n // if they're both in a circular reference\n return objectStack1.has(obj1) && objectStack2.has(obj2);\n }\n\n // Add objects to their respective stacks\n objectStack1.add(obj1);\n objectStack2.add(obj2);\n\n // Handle Date objects - needs to be before the class instance check\n if (value1 instanceof Date && value2 instanceof Date) {\n objectStack1.delete(obj1);\n objectStack2.delete(obj2);\n return value1.getTime() === value2.getTime();\n }\n\n // Handle RegExp objects - needs to be before the class instance check\n if (value1 instanceof RegExp && value2 instanceof RegExp) {\n objectStack1.delete(obj1);\n objectStack2.delete(obj2);\n return value1.toString() === value2.toString();\n }\n\n // If either is a class instance, use reference equality (already checked above)\n if (isClassInstance(value1) || isClassInstance(value2)) {\n // Clean up before returning\n objectStack1.delete(obj1);\n objectStack2.delete(obj2);\n return false;\n }\n\n // Handle arrays\n const isArray1 = Array.isArray(value1);\n const isArray2 = Array.isArray(value2);\n\n if (isArray1 !== isArray2) {\n // Clean up before returning\n objectStack1.delete(obj1);\n objectStack2.delete(obj2);\n return false;\n }\n\n if (isArray1 && isArray2) {\n const arr1 = value1 as unknown[];\n const arr2 = value2 as unknown[];\n\n if (arr1.length !== arr2.length) {\n // Clean up before returning\n objectStack1.delete(obj1);\n objectStack2.delete(obj2);\n return false;\n }\n\n // Check for circular references in the comparison context\n const pairKey: [unknown, unknown] = [value1, value2];\n if (compareStack.has(pairKey)) {\n // Clean up before returning\n objectStack1.delete(obj1);\n objectStack2.delete(obj2);\n return true;\n }\n compareStack.add(pairKey);\n\n // Compare each element\n for (let i = 0; i < arr1.length; i++) {\n if (!isEqual(arr1[i], arr2[i], compareStack, objectStack1, objectStack2)) {\n compareStack.delete(pairKey);\n // Clean up before returning\n objectStack1.delete(obj1);\n objectStack2.delete(obj2);\n return false;\n }\n }\n\n compareStack.delete(pairKey);\n objectStack1.delete(obj1);\n objectStack2.delete(obj2);\n return true;\n }\n\n // Handle plain objects\n const plainObj1 = value1 as Record<string, unknown>;\n const plainObj2 = value2 as Record<string, unknown>;\n\n const keys1 = Object.keys(plainObj1);\n const keys2 = Object.keys(plainObj2);\n\n // If key counts differ, objects aren't equal\n if (keys1.length !== keys2.length) {\n // Clean up before returning\n objectStack1.delete(obj1);\n objectStack2.delete(obj2);\n return false;\n }\n\n // Verify all keys in obj2 are in obj1 (we already checked counts, so this\n // also ensures all keys in obj1 are in obj2)\n for (const key of keys2) {\n if (!Object.prototype.hasOwnProperty.call(plainObj1, key)) {\n // Clean up before returning\n objectStack1.delete(obj1);\n objectStack2.delete(obj2);\n return false;\n }\n }\n\n // Check for circular references in the comparison context\n const pairKey: [unknown, unknown] = [value1, value2];\n if (compareStack.has(pairKey)) {\n // Clean up before returning\n objectStack1.delete(obj1);\n objectStack2.delete(obj2);\n return true;\n }\n compareStack.add(pairKey);\n\n // Compare each property's value\n for (const key of keys1) {\n if (\n !isEqual(plainObj1[key], plainObj2[key], compareStack, objectStack1, objectStack2)\n ) {\n compareStack.delete(pairKey);\n // Clean up before returning\n objectStack1.delete(obj1);\n objectStack2.delete(obj2);\n return false;\n }\n }\n\n compareStack.delete(pairKey);\n // Clean up before returning successful comparison\n objectStack1.delete(obj1);\n objectStack2.delete(obj2);\n return true;\n};\n\n/**\n * Generates a diff between original and modified objects.\n * This is used after the merge operation to track what has changed.\n */\nexport function generateDiff(original: unknown, modified: unknown): DiffNode | null {\n // Root diff node\n const diffRoot: DiffNode = { children: {} };\n\n // Compare the objects and build the diff tree\n compareAndBuildDiff(original, modified, diffRoot);\n\n // Clean up the diff tree (remove empty nodes)\n return cleanupDiffTree(diffRoot);\n}\n\n/**\n * Helper function to compare and build the diff tree\n */\nfunction compareAndBuildDiff(\n original: unknown,\n modified: unknown,\n parentDiffNode: DiffNode,\n key?: string | symbol,\n /**\n * Tracks pairs of objects being compared\n * - It stores pairs of values that are being compared `[original, modified]`\n * - This helps detect when we're comparing the same pair of objects again\n * - It prevents infinite recursion when comparing complex object structures\n */\n compareStack = new Set<[unknown, unknown]>(),\n /**\n * Tracks individual objects that are being processed in the current traversal path\n * - It's used to detect when we encounter the same object multiple times in a single traversal path\n * - This helps identify self-referential or circular structures within a single object (e.g., when an object references itself)\n * - When an object appears in `objectStack` again, we know it's a circular reference within the same object\n */\n objectStack = new Set<unknown>(),\n): void {\n // If values are equal, no diff to record\n if (isEqual(original, modified, new Set(compareStack))) {\n return;\n }\n\n // Handle additions (value in modified but not in original)\n if (original === undefined || original === null) {\n if (key !== undefined) {\n parentDiffNode.children[String(key)] = {\n type: 'added',\n value: modified,\n children: {},\n };\n }\n return;\n }\n\n // Check for circular references in objects\n if (typeof original === 'object' && original !== null) {\n if (objectStack.has(original)) {\n if (key !== undefined) {\n parentDiffNode.children[String(key)] = {\n type: 'circular',\n value: modified,\n oldValue: original,\n children: {},\n };\n }\n return;\n }\n objectStack.add(original);\n }\n\n // Check if we're dealing with non-objects or special object types that should be treated atomically\n const shouldTreatAtomically =\n typeof original !== 'object' ||\n typeof modified !== 'object' ||\n original === null ||\n modified === null ||\n Array.isArray(original) !== Array.isArray(modified) ||\n isClassInstance(original) ||\n isClassInstance(modified);\n\n if (shouldTreatAtomically) {\n if (key !== undefined) {\n parentDiffNode.children[String(key)] = {\n type: 'updated',\n value: modified,\n oldValue: original,\n children: {},\n };\n }\n\n // Remove from object stack if it was added\n if (typeof original === 'object' && original !== null) {\n objectStack.delete(original);\n }\n return;\n }\n\n // Handle objects\n const originalObj = original as Record<string | symbol, unknown>;\n const modifiedObj = modified as Record<string | symbol, unknown>;\n\n // Create a diff node for this level if we're processing a property\n const currentDiffNode =\n key !== undefined\n ? {\n type: 'updated' as ChangeType,\n children: {},\n oldValue: original,\n value: modified,\n }\n : parentDiffNode;\n\n if (key !== undefined) {\n parentDiffNode.children[String(key)] = currentDiffNode;\n }\n\n // Check for circular references in comparison\n const pairKey: [unknown, unknown] = [original, modified];\n if (compareStack.has(pairKey)) {\n // Remove from object stack before returning\n if (typeof original === 'object' && original !== null) {\n objectStack.delete(original);\n }\n return;\n }\n compareStack.add(pairKey);\n\n // Process all keys from both objects\n const allKeys = new Set([\n ...Object.keys(originalObj),\n ...Object.getOwnPropertySymbols(originalObj),\n ...Object.keys(modifiedObj),\n ...Object.getOwnPropertySymbols(modifiedObj),\n ]);\n\n for (const childKey of allKeys) {\n const originalValue = originalObj[childKey];\n const modifiedValue = modifiedObj[childKey];\n\n // Handle deleted properties (they exist in original but not in modified)\n if (!(childKey in modifiedObj)) {\n // Currently we don't track deletions, but could be added here if needed\n continue;\n }\n\n // Handle added properties (they exist in modified but not in original)\n if (!(childKey in originalObj)) {\n currentDiffNode.children[String(childKey)] = {\n type: 'added',\n value: modifiedValue,\n children: {},\n };\n continue;\n }\n\n // Process properties that exist in both but may have changed\n compareAndBuildDiff(\n originalValue,\n modifiedValue,\n currentDiffNode,\n childKey,\n compareStack,\n objectStack,\n );\n }\n\n compareStack.delete(pairKey);\n\n // Remove from object stack before returning\n if (typeof original === 'object' && original !== null) {\n objectStack.delete(original);\n }\n}\n\nexport function createMergeCore<T extends object>(options: { trackDiff?: boolean } = {}) {\n const { trackDiff = false } = options;\n\n return function mergeCore({\n target,\n source,\n customizer,\n }: {\n target: T;\n source: object | object[];\n customizer?: MergeWithCustomizer<T>;\n }): { result: T; diff: DiffNode | null } {\n const sources = Array.isArray(source) ? source : [source];\n\n // Store the original target if we need to track diffs\n const originalTarget = trackDiff ? structuredClone(target) : undefined;\n\n function handleCustomizer(\n targetValue: unknown,\n srcValue: unknown,\n sourceKey: string | symbol,\n target: object,\n src: object,\n stack: Set<unknown>,\n ): boolean {\n const customValue = customizer?.(\n targetValue,\n srcValue,\n sourceKey,\n target as T,\n src,\n stack,\n );\n if (customValue !== undefined) {\n Object.defineProperty(target, sourceKey, {\n value: customValue,\n enumerable: true,\n writable: true,\n configurable: true,\n });\n return true;\n }\n return false;\n }\n\n function createNewTarget(targetValue: unknown, srcValue: object): object {\n if (targetValue === null || typeof targetValue === 'undefined') {\n return srcValue;\n }\n if (!Array.isArray(targetValue) && typeof targetValue !== 'object') {\n return srcValue;\n }\n if (targetValue && typeof targetValue === 'object') {\n // Check if it's a class instance (not a plain object)\n const isTargetClassInstance = isClassInstance(targetValue);\n const isSourceClassInstance = isClassInstance(srcValue);\n\n // If either is a class instance, don't try to merge them\n if (isTargetClassInstance || isSourceClassInstance) {\n // If source is a class instance, use it\n if (isSourceClassInstance) {\n return srcValue as object;\n }\n // Otherwise preserve the target\n return targetValue;\n }\n\n // For plain objects, use normal merging\n return Array.isArray(targetValue) ? [...targetValue] : { ...targetValue };\n }\n return Array.isArray(srcValue) ? [] : {};\n }\n\n function processSourceValue(\n target: object,\n src: object,\n sourceKey: string | symbol,\n stack: Set<unknown>,\n pendingMerges: PendingMerge[],\n ): void {\n const srcValue = src[sourceKey as keyof typeof src];\n const targetValue = target[sourceKey as keyof typeof target];\n\n if (handleCustomizer(targetValue, srcValue, sourceKey, target, src, stack)) {\n return;\n }\n\n if (srcValue && typeof srcValue === 'object') {\n if (!stack.has(srcValue)) {\n const newTarget = createNewTarget(targetValue, srcValue);\n Object.defineProperty(target, sourceKey, {\n value: newTarget,\n enumerable: true,\n writable: true,\n configurable: true,\n });\n\n if (isClassInstance(newTarget)) return;\n\n pendingMerges.push({\n target: newTarget,\n source: srcValue,\n sourceKey,\n parentTarget: target,\n });\n }\n } else if (srcValue !== undefined) {\n target[sourceKey as keyof typeof target] = srcValue;\n }\n }\n\n function processKeys(\n target: object,\n source: object,\n stack: Set<unknown>,\n pendingMerges: PendingMerge[],\n ): void {\n const sourceKeys = [\n ...Object.keys(source),\n ...Object.getOwnPropertySymbols(source),\n ];\n for (const sourceKey of sourceKeys) {\n processSourceValue(target, source, sourceKey, stack, pendingMerges);\n }\n }\n\n function processPendingMerge(\n { target, source, sourceKey, parentTarget }: PendingMerge,\n stack: Set<unknown>,\n pendingMerges: PendingMerge[],\n ): void {\n if (stack.has(source)) {\n // We've detected a circular reference in the source object\n // Just skip this merge to avoid infinite recursion\n\n // If we're tracking diffs, we need to mark this as a circular reference\n if (trackDiff && sourceKey && parentTarget) {\n Object.defineProperty(parentTarget, sourceKey, {\n value: target,\n enumerable: true,\n writable: true,\n configurable: true,\n });\n }\n return;\n }\n\n if (!stack.has(target) && !stack.has(source)) {\n stack.add(target);\n stack.add(source);\n processKeys(target, source, stack, pendingMerges);\n stack.delete(source);\n stack.delete(target);\n }\n }\n\n function baseMerge(object: T, source: object, stack = new Set<unknown>()): T {\n // prevent infinite recursion\n if (stack.has(object) || stack.has(source)) {\n return { ...object };\n }\n\n const result = { ...object };\n const pendingMerges: PendingMerge[] = [];\n stack.add(result);\n stack.add(source);\n\n processKeys(result, source, stack, pendingMerges);\n\n while (pendingMerges.length) {\n // eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n processPendingMerge(pendingMerges.pop()!, stack, pendingMerges);\n }\n\n stack.delete(source);\n stack.delete(result);\n\n return result;\n }\n\n const result = sources.reduce<T>((result, source) => baseMerge(result, source) as T, {\n ...target,\n } as T);\n\n // If diff tracking is enabled, generate the diff after the merge is complete\n const diff =\n trackDiff && originalTarget ? generateDiff(originalTarget, result) : null;\n\n return { result, diff };\n };\n}\n\n// Utility function to clean up the diff tree by removing empty child nodes\nexport function cleanupDiffTree(diffNode: DiffNode): DiffNode | null {\n const cleanChildren: Record<string | symbol, DiffNode> = {};\n let hasChildren = false;\n\n for (const key in diffNode.children) {\n const childNode = cleanupDiffTree(diffNode.children[key]);\n if (childNode) {\n cleanChildren[key] = childNode;\n hasChildren = true;\n }\n }\n\n // If this node has a type (added/updated) or has children, keep it\n if (diffNode.type || hasChildren) {\n return {\n ...diffNode,\n children: cleanChildren,\n };\n }\n\n return null;\n}\n", "/**\n * This method is like `_.merge` except that it accepts `customizer` which\n * is invoked to produce the merged values of the destination and source\n * properties. If `customizer` returns `undefined` merging is handled by the\n * method instead. The `customizer` is invoked with seven arguments:\n * (objValue, srcValue, key, object, source, stack).\n *\n * @category Object\n * @param object The destination object.\n * @param source A single source object or an array of objects to be merged into the .\n * @param customizer The function to customize assigned values.\n * @returns Returns `object`.\n * @example\n *\n * function customizer(objValue, srcValue) {\n * if (_.isArray(objValue)) {\n * return objValue.concat(srcValue);\n * }\n * }\n *\n * var object = {\n * 'fruits': ['apple'],\n * 'vegetables': ['beet']\n * };\n *\n * var other = {\n * 'fruits': ['banana'],\n * 'vegetables': ['carrot']\n * };\n *\n * _.mergeWith(object, other, customizer);\n * // => { 'fruits': ['apple', 'banana'], 'vegetables': ['beet', 'carrot'] }\n */\nimport type { MergeWithCustomizer } from './mergeWithCore';\nimport { createMergeCore } from './mergeWithCore';\n\nexport function mergeWith<T extends object>(\n target: T,\n source: object | object[],\n customizer?: MergeWithCustomizer<T>,\n): T {\n const mergeCore = createMergeCore<T>();\n return mergeCore({ target, source, customizer }).result;\n}\n", "/**\n * This method is like `mergeWith` except that it also returns information about\n * which keys have been added or updated during the merge operation.\n *\n * @category Object\n * @param object The destination object.\n * @param source A single source object or an array of objects to be merged into the object.\n * @param customizer The function to customize assigned values.\n * @returns Returns an object containing the merged result and a hierarchical diff object.\n * @example\n *\n * function customizer(objValue, srcValue) {\n * if (Array.isArray(objValue)) {\n * return objValue.concat(srcValue);\n * }\n * }\n *\n * var object = {\n * 'fruits': ['apple'],\n * 'vegetables': ['beet']\n * };\n *\n * var other = {\n * 'fruits': ['banana'],\n * 'vegetables': ['carrot'],\n * 'grains': ['wheat']\n * };\n *\n * const { result, diff } = mergeWithDiff({ target: object, source: other, customizer });\n * // result => { 'fruits': ['apple', 'banana'], 'vegetables': ['beet', 'carrot'], 'grains': ['wheat'] }\n * // diff => {\n * // children: {\n * // 'fruits': { type: 'updated', value: ['banana'], oldValue: ['apple'], children: {} },\n * // 'vegetables': { type: 'updated', value: ['carrot'], oldValue: ['beet'], children: {} },\n * // 'grains': { type: 'added', value: ['wheat'], children: {} }\n * // }\n * // }\n */\nimport { cleanupDiffTree, createMergeCore } from './mergeWithCore';\nimport type { DiffNode, MergeWithCustomizer } from './mergeWithCore';\n\nexport function mergeWithDiff<T extends object>(\n target: T,\n source: object | object[],\n customizer?: MergeWithCustomizer<T>,\n): { result: T; diff: DiffNode } {\n const mergeCore = createMergeCore<T>({ trackDiff: true });\n const { result, diff } = mergeCore({ target, source, customizer });\n\n // Clean up the diff tree to remove empty nodes\n\n return { result, diff: cleanupDiffTree(diff ?? { children: {} }) || { children: {} } };\n}\n", "import type {\n AttachmentManagerConfig,\n MinimumUploadRequestResult,\n UploadRequestFn,\n} from './configuration';\nimport { isLocalImageAttachment, isUploadedAttachment } from './attachmentIdentity';\nimport {\n createFileFromBlobs,\n ensureIsLocalAttachment,\n generateFileName,\n getAttachmentTypeFromMimeType,\n isFile,\n isFileList,\n isFileReference,\n isImageFile,\n} from './fileUtils';\nimport {\n AttachmentPostUploadMiddlewareExecutor,\n AttachmentPreUploadMiddlewareExecutor,\n} from './middleware/attachmentManager';\nimport { StateStore } from '../store';\nimport { generateUUIDv4 } from '../utils';\nimport { DEFAULT_UPLOAD_SIZE_LIMIT_BYTES } from '../constants';\nimport type {\n AttachmentLoadingState,\n FileLike,\n FileReference,\n LocalAttachment,\n LocalNotImageAttachment,\n LocalUploadAttachment,\n UploadPermissionCheckResult,\n} from './types';\nimport type { ChannelResponse, DraftMessage, LocalMessage } from '../types';\nimport type { MessageComposer } from './messageComposer';\nimport { mergeWithDiff } from '../utils/mergeWith';\n\nexport type FileUploadFilter = (file: Partial<LocalUploadAttachment>) => boolean;\n\nexport type AttachmentManagerState = {\n attachments: LocalAttachment[];\n};\n\nexport type AttachmentManagerOptions = {\n composer: MessageComposer;\n message?: DraftMessage | LocalMessage;\n};\n\nconst initState = ({\n message,\n}: {\n message?: DraftMessage | LocalMessage;\n}): AttachmentManagerState => ({\n attachments: (message?.attachments ?? [])\n ?.filter(({ og_scrape_url }) => !og_scrape_url)\n .map((att) => {\n const localMetadata = isUploadedAttachment(att)\n ? { id: generateUUIDv4(), uploadState: 'finished' }\n : { id: generateUUIDv4() };\n return {\n ...att,\n localMetadata,\n } as LocalAttachment;\n }),\n});\n\nexport class AttachmentManager {\n readonly state: StateStore<AttachmentManagerState>;\n readonly composer: MessageComposer;\n readonly preUploadMiddlewareExecutor: AttachmentPreUploadMiddlewareExecutor;\n readonly postUploadMiddlewareExecutor: AttachmentPostUploadMiddlewareExecutor;\n private attachmentsByIdGetterCache: {\n attachmentsById: Record<string, LocalAttachment>;\n attachments: LocalAttachment[];\n };\n\n constructor({ composer, message }: AttachmentManagerOptions) {\n this.composer = composer;\n this.state = new StateStore<AttachmentManagerState>(initState({ message }));\n this.attachmentsByIdGetterCache = { attachmentsById: {}, attachments: [] };\n\n this.preUploadMiddlewareExecutor = new AttachmentPreUploadMiddlewareExecutor({\n composer,\n });\n this.postUploadMiddlewareExecutor = new AttachmentPostUploadMiddlewareExecutor({\n composer,\n });\n }\n\n get attachmentsById() {\n const { attachments } = this.state.getLatestValue();\n\n if (attachments !== this.attachmentsByIdGetterCache.attachments) {\n this.attachmentsByIdGetterCache.attachments = attachments;\n this.attachmentsByIdGetterCache.attachmentsById = attachments.reduce<\n Record<string, LocalAttachment>\n >((newAttachmentsById, attachment) => {\n // should never happen but does not hurt to check\n if (!attachment.localMetadata.id) return newAttachmentsById;\n\n newAttachmentsById[attachment.localMetadata.id] ??= attachment;\n\n return newAttachmentsById;\n }, {});\n }\n\n return this.attachmentsByIdGetterCache.attachmentsById;\n }\n\n get client() {\n return this.composer.client;\n }\n\n get channel() {\n return this.composer.channel;\n }\n\n get config() {\n return this.composer.config.attachments;\n }\n\n get acceptedFiles() {\n return this.config.acceptedFiles;\n }\n\n set acceptedFiles(acceptedFiles: AttachmentManagerConfig['acceptedFiles']) {\n this.composer.updateConfig({ attachments: { acceptedFiles } });\n }\n\n /*\n @deprecated attachments can be filtered using injecting pre-upload middleware\n */\n get fileUploadFilter() {\n return this.config.fileUploadFilter;\n }\n\n /*\n @deprecated attachments can be filtered using injecting pre-upload middleware\n */\n set fileUploadFilter(fileUploadFilter: AttachmentManagerConfig['fileUploadFilter']) {\n this.composer.updateConfig({ attachments: { fileUploadFilter } });\n }\n\n get maxNumberOfFilesPerMessage() {\n return this.config.maxNumberOfFilesPerMessage;\n }\n\n set maxNumberOfFilesPerMessage(\n maxNumberOfFilesPerMessage: AttachmentManagerConfig['maxNumberOfFilesPerMessage'],\n ) {\n if (maxNumberOfFilesPerMessage === this.maxNumberOfFilesPerMessage) return;\n this.composer.updateConfig({ attachments: { maxNumberOfFilesPerMessage } });\n }\n\n setCustomUploadFn = (doUploadRequest: UploadRequestFn) => {\n this.composer.updateConfig({ attachments: { doUploadRequest } });\n };\n\n get attachments() {\n return this.state.getLatestValue().attachments;\n }\n\n get hasUploadPermission() {\n return !!(\n this.channel.data?.own_capabilities as ChannelResponse['own_capabilities']\n )?.includes('upload-file');\n }\n\n get isUploadEnabled() {\n return this.hasUploadPermission && this.availableUploadSlots > 0;\n }\n\n get successfulUploads() {\n return this.getUploadsByState('finished');\n }\n\n get successfulUploadsCount() {\n return this.successfulUploads.length;\n }\n\n get uploadsInProgressCount() {\n return this.getUploadsByState('uploading').length;\n }\n\n get failedUploadsCount() {\n return this.getUploadsByState('failed').length;\n }\n\n get blockedUploadsCount() {\n return this.getUploadsByState('blocked').length;\n }\n\n get pendingUploadsCount() {\n return this.getUploadsByState('pending').length;\n }\n\n get availableUploadSlots() {\n return (\n this.config.maxNumberOfFilesPerMessage -\n this.successfulUploadsCount -\n this.uploadsInProgressCount\n );\n }\n\n getUploadsByState(state: AttachmentLoadingState) {\n return Object.values(this.attachments).filter(\n ({ localMetadata }) => localMetadata.uploadState === state,\n );\n }\n\n initState = ({ message }: { message?: DraftMessage | LocalMessage } = {}) => {\n this.state.next(initState({ message }));\n };\n\n getAttachmentIndex = (localId: string) => {\n const attachmentsById = this.attachmentsById;\n\n return this.attachments.indexOf(attachmentsById[localId]);\n };\n\n private prepareAttachmentUpdate = (attachmentToUpdate: LocalAttachment) => {\n const stateAttachments = this.attachments;\n const attachments = [...this.attachments];\n const attachmentIndex = this.getAttachmentIndex(attachmentToUpdate.localMetadata.id);\n if (attachmentIndex === -1) return null;\n // do not re-organize newAttachments array otherwise indexing would no longer work\n // replace in place only with the attachments with the same id's\n const merged = mergeWithDiff<LocalAttachment>(\n stateAttachments[attachmentIndex],\n attachmentToUpdate,\n );\n const updatesOnMerge = merged.diff && Object.keys(merged.diff.children).length;\n if (updatesOnMerge) {\n const localAttachment = ensureIsLocalAttachment(merged.result);\n if (localAttachment) {\n attachments.splice(attachmentIndex, 1, localAttachment);\n return attachments;\n }\n }\n return null;\n };\n\n updateAttachment = (attachmentToUpdate: LocalAttachment) => {\n const updatedAttachments = this.prepareAttachmentUpdate(attachmentToUpdate);\n if (updatedAttachments) {\n this.state.partialNext({ attachments: updatedAttachments });\n }\n };\n\n upsertAttachments = (attachmentsToUpsert: LocalAttachment[]) => {\n if (!attachmentsToUpsert.length) return;\n let attachments = [...this.attachments];\n let hasUpdates = false;\n attachmentsToUpsert.forEach((attachment) => {\n const updatedAttachments = this.prepareAttachmentUpdate(attachment);\n if (updatedAttachments) {\n attachments = updatedAttachments;\n hasUpdates = true;\n } else {\n const localAttachment = ensureIsLocalAttachment(attachment);\n if (localAttachment) {\n attachments.push(localAttachment);\n hasUpdates = true;\n }\n }\n });\n if (hasUpdates) {\n this.state.partialNext({ attachments });\n }\n };\n\n removeAttachments = (localAttachmentIds: string[]) => {\n this.state.partialNext({\n attachments: this.attachments.filter(\n (attachment) => !localAttachmentIds.includes(attachment.localMetadata?.id),\n ),\n });\n };\n\n getUploadConfigCheck = async (\n fileLike: FileReference | FileLike,\n ): Promise<UploadPermissionCheckResult> => {\n const client = this.channel.getClient();\n let appSettings;\n if (!client.appSettingsPromise) {\n appSettings = await client.getAppSettings();\n } else {\n appSettings = await client.appSettingsPromise;\n }\n const uploadConfig = isImageFile(fileLike)\n ? appSettings?.app?.image_upload_config\n : appSettings?.app?.file_upload_config;\n if (!uploadConfig) return { uploadBlocked: false };\n\n const {\n allowed_file_extensions,\n allowed_mime_types,\n blocked_file_extensions,\n blocked_mime_types,\n size_limit,\n } = uploadConfig;\n\n const sizeLimit = size_limit || DEFAULT_UPLOAD_SIZE_LIMIT_BYTES;\n const mimeType = fileLike.type;\n\n if (isFile(fileLike) || isFileReference(fileLike)) {\n if (\n allowed_file_extensions?.length &&\n !allowed_file_extensions.some((ext) =>\n fileLike.name.toLowerCase().endsWith(ext.toLowerCase()),\n )\n ) {\n return { uploadBlocked: true, reason: 'allowed_file_extensions' };\n }\n\n if (\n blocked_file_extensions?.length &&\n blocked_file_extensions.some((ext) =>\n fileLike.name.toLowerCase().endsWith(ext.toLowerCase()),\n )\n ) {\n return { uploadBlocked: true, reason: 'blocked_file_extensions' };\n }\n }\n\n if (\n allowed_mime_types?.length &&\n !allowed_mime_types.some((type) => type.toLowerCase() === mimeType?.toLowerCase())\n ) {\n return { uploadBlocked: true, reason: 'allowed_mime_types' };\n }\n\n if (\n blocked_mime_types?.length &&\n blocked_mime_types.some((type) => type.toLowerCase() === mimeType?.toLowerCase())\n ) {\n return { uploadBlocked: true, reason: 'blocked_mime_types' };\n }\n\n if (fileLike.size && fileLike.size > sizeLimit) {\n return { uploadBlocked: true, reason: 'size_limit' };\n }\n\n return { uploadBlocked: false };\n };\n\n static toLocalUploadAttachment = (\n fileLike: FileReference | FileLike,\n ): LocalUploadAttachment => {\n const file =\n isFileReference(fileLike) || isFile(fileLike)\n ? fileLike\n : createFileFromBlobs({\n blobsArray: [fileLike],\n fileName: generateFileName(fileLike.type),\n mimeType: fileLike.type,\n });\n\n const localAttachment: LocalUploadAttachment = {\n file_size: file.size,\n mime_type: file.type,\n localMetadata: {\n file,\n id: generateUUIDv4(),\n uploadState: 'pending',\n },\n type: getAttachmentTypeFromMimeType(file.type),\n };\n\n localAttachment[isImageFile(file) ? 'fallback' : 'title'] = file.name;\n\n if (isImageFile(file)) {\n localAttachment.localMetadata.previewUri = isFileReference(fileLike)\n ? fileLike.uri\n : URL.createObjectURL?.(fileLike);\n\n if (isFileReference(fileLike) && fileLike.height && fileLike.width) {\n localAttachment.original_height = fileLike.height;\n localAttachment.original_width = fileLike.width;\n }\n }\n\n if (isFileReference(fileLike) && fileLike.thumb_url) {\n localAttachment.thumb_url = fileLike.thumb_url;\n }\n\n if (isFileReference(fileLike) && fileLike.duration) {\n localAttachment.duration = fileLike.duration;\n }\n\n return localAttachment;\n };\n\n // @deprecated use AttachmentManager.toLocalUploadAttachment(file)\n fileToLocalUploadAttachment = async (\n fileLike: FileReference | FileLike,\n ): Promise<LocalUploadAttachment> => {\n const localAttachment = AttachmentManager.toLocalUploadAttachment(fileLike);\n const uploadPermissionCheck = await this.getUploadConfigCheck(\n localAttachment.localMetadata.file,\n );\n localAttachment.localMetadata.uploadPermissionCheck = uploadPermissionCheck;\n localAttachment.localMetadata.uploadState = uploadPermissionCheck.uploadBlocked\n ? 'blocked'\n : 'pending';\n\n return localAttachment;\n };\n\n private ensureLocalUploadAttachment = async (\n attachment: Partial<LocalUploadAttachment>,\n ) => {\n if (!attachment.localMetadata?.file) {\n this.client.notifications.addError({\n message: 'File is required for upload attachment',\n origin: { emitter: 'AttachmentManager', context: { attachment } },\n options: { type: 'validation:attachment:file:missing' },\n });\n return;\n }\n\n if (!attachment.localMetadata.id) {\n this.client.notifications.addError({\n message: 'Local upload attachment missing local id',\n origin: { emitter: 'AttachmentManager', context: { attachment } },\n options: { type: 'validation:attachment:id:missing' },\n });\n return;\n }\n\n if (!this.fileUploadFilter(attachment)) return;\n\n const newAttachment = await this.fileToLocalUploadAttachment(\n attachment.localMetadata.file,\n );\n if (attachment.localMetadata.id) {\n newAttachment.localMetadata.id = attachment.localMetadata.id;\n }\n return newAttachment;\n };\n\n /**\n * Method to perform the default upload behavior without checking for custom upload functions\n * to prevent recursive calls\n */\n doDefaultUploadRequest = async (fileLike: FileReference | FileLike) => {\n if (isFileReference(fileLike)) {\n return this.channel[isImageFile(fileLike) ? 'sendImage' : 'sendFile'](\n fileLike.uri,\n fileLike.name,\n fileLike.type,\n );\n }\n\n const file = isFile(fileLike)\n ? fileLike\n : createFileFromBlobs({\n blobsArray: [fileLike],\n fileName: generateFileName(fileLike.type),\n mimeType: fileLike.type,\n });\n\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n const { duration, ...result } =\n await this.channel[isImageFile(fileLike) ? 'sendImage' : 'sendFile'](file);\n return result;\n };\n\n /**\n * todo: docs how to customize the image and file upload by overriding do\n */\n\n doUploadRequest = async (fileLike: FileReference | FileLike) => {\n const customUploadFn = this.config.doUploadRequest;\n if (customUploadFn) {\n return await customUploadFn(fileLike);\n }\n\n return this.doDefaultUploadRequest(fileLike);\n };\n\n // @deprecated use attachmentManager.uploadFile(file)\n uploadAttachment = async (attachment: LocalUploadAttachment) => {\n if (!this.isUploadEnabled) return;\n\n const localAttachment = await this.ensureLocalUploadAttachment(attachment);\n\n if (typeof localAttachment === 'undefined') return;\n\n if (localAttachment.localMetadata.uploadState === 'blocked') {\n this.upsertAttachments([localAttachment]);\n this.client.notifications.addError({\n message: `The attachment upload was blocked`,\n origin: {\n emitter: 'AttachmentManager',\n context: { attachment, blockedAttachment: localAttachment },\n },\n options: {\n type: 'validation:attachment:upload:blocked',\n metadata: {\n reason: localAttachment.localMetadata.uploadPermissionCheck?.reason,\n },\n },\n });\n return localAttachment;\n }\n\n this.upsertAttachments([\n {\n ...attachment,\n localMetadata: {\n ...attachment.localMetadata,\n uploadState: 'uploading',\n },\n },\n ]);\n\n let response: MinimumUploadRequestResult;\n try {\n response = await this.doUploadRequest(localAttachment.localMetadata.file);\n } catch (error) {\n const reason = error instanceof Error ? error.message : 'unknown error';\n const failedAttachment: LocalUploadAttachment = {\n ...attachment,\n localMetadata: {\n ...attachment.localMetadata,\n uploadState: 'failed',\n },\n };\n\n this.client.notifications.addError({\n message: 'Error uploading attachment',\n origin: {\n emitter: 'AttachmentManager',\n context: { attachment, failedAttachment },\n },\n options: {\n type: 'api:attachment:upload:failed',\n metadata: { reason },\n originalError: error instanceof Error ? error : undefined,\n },\n });\n\n this.updateAttachment(failedAttachment);\n return failedAttachment;\n }\n\n if (!response) {\n // Copied this from useImageUpload / useFileUpload.\n\n // If doUploadRequest returns any falsy value, then don't create the upload preview.\n // This is for the case if someone wants to handle failure on app level.\n this.removeAttachments([attachment.localMetadata.id]);\n return;\n }\n\n const uploadedAttachment: LocalUploadAttachment = {\n ...attachment,\n localMetadata: {\n ...attachment.localMetadata,\n uploadState: 'finished',\n },\n };\n\n if (isLocalImageAttachment(uploadedAttachment)) {\n if (uploadedAttachment.localMetadata.previewUri) {\n URL.revokeObjectURL(uploadedAttachment.localMetadata.previewUri);\n delete uploadedAttachment.localMetadata.previewUri;\n }\n uploadedAttachment.image_url = response.file;\n } else {\n (uploadedAttachment as LocalNotImageAttachment).asset_url = response.file;\n }\n if (response.thumb_url) {\n (uploadedAttachment as LocalNotImageAttachment).thumb_url = response.thumb_url;\n }\n\n this.updateAttachment(uploadedAttachment);\n\n return uploadedAttachment;\n };\n\n uploadFile = async (file: FileReference | FileLike) => {\n const preUpload = await this.preUploadMiddlewareExecutor.execute({\n eventName: 'prepare',\n initialValue: {\n attachment: AttachmentManager.toLocalUploadAttachment(file),\n },\n mode: 'concurrent',\n });\n\n let attachment: LocalUploadAttachment = preUpload.state.attachment;\n\n if (preUpload.status === 'discard') return attachment;\n // todo: remove with the next major release as filtering can be done in middleware\n // should we return the attachment object?\n if (!this.fileUploadFilter(attachment)) return attachment;\n\n if (attachment.localMetadata.uploadState === 'blocked') {\n this.upsertAttachments([attachment]);\n return preUpload.state.attachment;\n }\n\n attachment = {\n ...attachment,\n localMetadata: {\n ...attachment.localMetadata,\n uploadState: 'uploading',\n },\n };\n this.upsertAttachments([attachment]);\n\n let response: MinimumUploadRequestResult | undefined;\n let error: Error | undefined;\n try {\n response = await this.doUploadRequest(file);\n } catch (err) {\n error = err instanceof Error ? err : undefined;\n }\n\n const postUpload = await this.postUploadMiddlewareExecutor.execute({\n eventName: 'postProcess',\n initialValue: {\n attachment: {\n ...attachment,\n localMetadata: {\n ...attachment.localMetadata,\n uploadState: error ? 'failed' : 'finished',\n },\n },\n error,\n response,\n },\n mode: 'concurrent',\n });\n attachment = postUpload.state.attachment;\n\n if (postUpload.status === 'discard') {\n this.removeAttachments([attachment.localMetadata.id]);\n return attachment;\n }\n\n this.updateAttachment(attachment);\n return attachment;\n };\n\n uploadFiles = async (files: FileReference[] | FileList | FileLike[]) => {\n if (!this.isUploadEnabled) return;\n const iterableFiles: FileReference[] | FileLike[] = isFileList(files)\n ? Array.from(files)\n : files;\n\n return await Promise.all(\n iterableFiles.slice(0, this.availableUploadSlots).map(this.uploadFile),\n );\n };\n}\n", "import { find } from 'linkifyjs';\nimport { API_MAX_FILES_ALLOWED_PER_MESSAGE } from '../../constants';\nimport type {\n AttachmentManagerConfig,\n LinkPreviewsManagerConfig,\n LocationComposerConfig,\n MessageComposerConfig,\n} from './types';\nimport type { TextComposerConfig } from './types';\nimport { generateUUIDv4 } from '../../utils';\n\nexport const DEFAULT_LINK_PREVIEW_MANAGER_CONFIG: LinkPreviewsManagerConfig = {\n debounceURLEnrichmentMs: 1500,\n enabled: false,\n findURLFn: (text: string): string[] =>\n find(text, 'url', { defaultProtocol: 'https' }).reduce<string[]>((acc, link) => {\n try {\n const url = new URL(link.href);\n // Check for valid hostname with at least one dot and valid TLD\n if (link.isLink && /^[a-zA-Z0-9-.]+\\.[a-zA-Z]{2,}$/.test(url.hostname)) {\n acc.push(link.href);\n }\n } catch {\n // Invalid URL, skip it\n }\n return acc;\n }, []),\n};\n\nexport const DEFAULT_ATTACHMENT_MANAGER_CONFIG: AttachmentManagerConfig = {\n acceptedFiles: [], // an empty array means all files are accepted\n fileUploadFilter: () => true,\n maxNumberOfFilesPerMessage: API_MAX_FILES_ALLOWED_PER_MESSAGE,\n};\n\nexport const DEFAULT_TEXT_COMPOSER_CONFIG: TextComposerConfig = {\n enabled: true,\n publishTypingEvents: true,\n};\n\nexport const DEFAULT_LOCATION_COMPOSER_CONFIG: LocationComposerConfig = {\n enabled: true,\n getDeviceId: () => generateUUIDv4(),\n};\n\nexport const DEFAULT_COMPOSER_CONFIG: MessageComposerConfig = {\n attachments: DEFAULT_ATTACHMENT_MANAGER_CONFIG,\n drafts: { enabled: false },\n linkPreviews: DEFAULT_LINK_PREVIEW_MANAGER_CONFIG,\n location: DEFAULT_LOCATION_COMPOSER_CONFIG,\n text: DEFAULT_TEXT_COMPOSER_CONFIG,\n};\n", "import { StateStore } from '..';\nimport type {\n CustomMessageComposerData,\n CustomMessageData,\n DraftMessage,\n LocalMessage,\n} from '..';\nimport type { MessageComposer } from './messageComposer';\nimport type { DeepPartial } from '../types.utility';\n\nexport type CustomDataManagerState = {\n message: CustomMessageData;\n custom: CustomMessageComposerData;\n};\n\nexport type CustomDataManagerOptions = {\n composer: MessageComposer;\n message?: DraftMessage | LocalMessage;\n};\n\nconst initState = (options: CustomDataManagerOptions): CustomDataManagerState => {\n if (!options)\n return { message: {} as CustomMessageData, custom: {} as CustomMessageComposerData };\n return { message: {} as CustomMessageData, custom: {} as CustomMessageComposerData };\n};\n\nexport class CustomDataManager {\n composer: MessageComposer;\n state: StateStore<CustomDataManagerState>;\n\n constructor({ composer, message }: CustomDataManagerOptions) {\n this.composer = composer;\n this.state = new StateStore<CustomDataManagerState>(initState({ composer, message }));\n }\n\n get customMessageData() {\n return this.state.getLatestValue().message;\n }\n\n get customComposerData() {\n return this.state.getLatestValue().custom;\n }\n\n isMessageDataEqual = (\n nextState: CustomDataManagerState,\n previousState?: CustomDataManagerState,\n ) => JSON.stringify(nextState.message) === JSON.stringify(previousState?.message);\n\n initState = ({ message }: { message?: DraftMessage | LocalMessage } = {}) => {\n this.state.next(initState({ composer: this.composer, message }));\n };\n\n setMessageData(data: DeepPartial<CustomMessageData>) {\n this.state.partialNext({\n message: {\n ...this.state.getLatestValue().message,\n ...data,\n },\n });\n }\n\n setCustomData(data: DeepPartial<CustomMessageComposerData>) {\n this.state.partialNext({\n custom: {\n ...this.state.getLatestValue().custom,\n ...data,\n },\n });\n }\n}\n", "import { StateStore } from '../store';\nimport type { DebouncedFunc } from '../utils';\nimport { debounce } from '../utils';\nimport { mergeWithDiff } from '../utils/mergeWith';\nimport type { DraftMessage, LocalMessage, OGAttachment } from '../types';\nimport type { LinkPreviewsManagerConfig } from './configuration/types';\nimport type { MessageComposer } from './messageComposer';\n\nexport type LinkPreview = OGAttachment & {\n status: LinkPreviewStatus;\n};\n\nexport interface ILinkPreviewsManager {\n /** Function cancels all the scheduled or in-progress URL enrichment queries and resets the state. */\n cancelURLEnrichment: () => void;\n /** Function that triggers the search for URLs and their enrichment. */\n findAndEnrichUrls?: DebouncedFunc<(text: string) => void>;\n}\n\nexport enum LinkPreviewStatus {\n /** Link preview has been dismissed using **/\n DISMISSED = 'dismissed',\n /** Link preview could not be loaded, the enrichment request has failed. **/\n FAILED = 'failed',\n /** Link preview has been successfully loaded. **/\n LOADED = 'loaded',\n /** The enrichment query is in progress for a given link. **/\n LOADING = 'loading',\n /** The preview reference enrichment has not begun. Default status if not set. */\n PENDING = 'pending',\n}\n\nexport type LinkURL = string;\n\nexport type LinkPreviewMap = Map<LinkURL, LinkPreview>;\n\nexport type LinkPreviewsManagerState = {\n previews: LinkPreviewMap;\n};\n\nexport type LinkPreviewsManagerOptions = {\n composer: MessageComposer;\n message?: DraftMessage | LocalMessage;\n};\n\nconst linkPreviewArrayToMap = (linkPreviews: LinkPreview[]) =>\n new Map(linkPreviews.map((linkPreview) => [linkPreview.og_scrape_url, linkPreview]));\n\nconst initState = ({\n message,\n}: {\n message?: DraftMessage | LocalMessage;\n}): LinkPreviewsManagerState =>\n message\n ? {\n previews:\n message.attachments?.reduce<LinkPreviewMap>((acc, attachment) => {\n if (!attachment.og_scrape_url) return acc;\n acc.set(attachment.og_scrape_url, {\n ...(attachment as OGAttachment),\n status: LinkPreviewStatus.LOADED,\n });\n return acc;\n }, new Map()) ?? new Map(),\n }\n : {\n previews: new Map<LinkURL, LinkPreview>(),\n };\n\n/*\ndocs:\nYou can customize function to identify URLs in a string and request OG data by overriding findURLFn?: (text: string) => string[];\n */\n\nexport class LinkPreviewsManager implements ILinkPreviewsManager {\n findAndEnrichUrls: DebouncedFunc<(text: string) => void>;\n readonly state: StateStore<LinkPreviewsManagerState>;\n readonly composer: MessageComposer;\n private shouldDiscardEnrichQueries = false;\n\n constructor({ composer, message }: LinkPreviewsManagerOptions) {\n this.composer = composer;\n this.state = new StateStore<LinkPreviewsManagerState>(\n initState({ message: this.enabled ? message : undefined }),\n );\n\n this.findAndEnrichUrls = debounce(\n this._findAndEnrichUrls.bind(this),\n this.config.debounceURLEnrichmentMs,\n );\n }\n\n get client() {\n return this.composer.client;\n }\n\n get channel() {\n return this.composer.channel;\n }\n\n get previews() {\n return this.state.getLatestValue().previews;\n }\n\n get loadingPreviews() {\n return Array.from(this.previews.values()).filter((linkPreview) =>\n LinkPreviewsManager.previewIsLoading(linkPreview),\n );\n }\n\n get loadedPreviews() {\n return Array.from(this.previews.values()).filter((linkPreview) =>\n LinkPreviewsManager.previewIsLoaded(linkPreview),\n );\n }\n\n get dismissedPreviews() {\n return Array.from(this.previews.values()).filter((linkPreview) =>\n LinkPreviewsManager.previewIsDismissed(linkPreview),\n );\n }\n\n get failedPreviews() {\n return Array.from(this.previews.values()).filter((linkPreview) =>\n LinkPreviewsManager.previewIsFailed(linkPreview),\n );\n }\n\n get pendingPreviews() {\n return Array.from(this.previews.values()).filter((linkPreview) =>\n LinkPreviewsManager.previewIsPending(linkPreview),\n );\n }\n\n get config() {\n return this.composer.config.linkPreviews;\n }\n\n get debounceURLEnrichmentMs() {\n return this.config.debounceURLEnrichmentMs;\n }\n\n set debounceURLEnrichmentMs(\n debounceURLEnrichmentMs: LinkPreviewsManagerConfig['debounceURLEnrichmentMs'],\n ) {\n this.cancelURLEnrichment();\n\n this.findAndEnrichUrls = debounce(\n this._findAndEnrichUrls.bind(this),\n this.config.debounceURLEnrichmentMs,\n );\n\n this.composer.updateConfig({ linkPreviews: { debounceURLEnrichmentMs } });\n }\n\n get enabled() {\n /**\n * We have to check whether the message will be enriched server side (url_enrichment).\n * If not, then it does not make sense to do previews in composer.\n */\n return (\n !!this.channel.getConfig()?.url_enrichment &&\n this.composer.config.linkPreviews.enabled\n );\n }\n\n set enabled(enabled: LinkPreviewsManagerConfig['enabled']) {\n if (enabled === this.enabled) return;\n this.composer.updateConfig({ linkPreviews: { enabled } });\n }\n\n get findURLFn() {\n return this.config.findURLFn;\n }\n\n set findURLFn(fn: LinkPreviewsManagerConfig['findURLFn']) {\n this.composer.updateConfig({ linkPreviews: { findURLFn: fn } });\n }\n\n get onLinkPreviewDismissed() {\n return this.config.onLinkPreviewDismissed;\n }\n\n set onLinkPreviewDismissed(fn: LinkPreviewsManagerConfig['onLinkPreviewDismissed']) {\n this.composer.updateConfig({ linkPreviews: { onLinkPreviewDismissed: fn } });\n }\n\n initState = ({ message }: { message?: DraftMessage | LocalMessage } = {}) => {\n this.state.next(initState({ message: this.enabled ? message : undefined }));\n };\n\n private _findAndEnrichUrls = async (text: string) => {\n if (!this.enabled) return;\n const urls = this.config.findURLFn(text);\n\n this.shouldDiscardEnrichQueries = !urls.length;\n if (this.shouldDiscardEnrichQueries) {\n this.state.next({ previews: new Map() });\n return;\n }\n const keptPreviews = new Map(\n Array.from(this.previews).filter(\n ([previewUrl]) => urls.includes(previewUrl) || urls.includes(previewUrl + '/'),\n ),\n );\n\n const newLinkPreviews = urls\n .filter((url) => {\n const existingPreviews = this.previews;\n // account for trailing slashes added by the back-end\n const existingPreviewLink =\n existingPreviews.get(url) || existingPreviews.get(url + '/');\n return !existingPreviewLink;\n })\n .map(\n (url) =>\n ({\n og_scrape_url: url.trim(),\n status: LinkPreviewStatus.LOADING,\n }) as LinkPreview,\n );\n\n if (!newLinkPreviews.length) return;\n\n this.state.partialNext({\n previews: new Map([...keptPreviews, ...linkPreviewArrayToMap(newLinkPreviews)]),\n });\n\n await Promise.all(\n newLinkPreviews.map(async (linkPreview) => {\n try {\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n const { duration, ...ogAttachment } = await this.client.enrichURL(\n linkPreview.og_scrape_url,\n );\n if (this.shouldDiscardEnrichQueries) return;\n // due to typing and text changes, the URL may not be anymore in the store\n if (this.previews.has(linkPreview.og_scrape_url)) {\n this.updatePreview(linkPreview.og_scrape_url, {\n status: LinkPreviewStatus.LOADED,\n ...ogAttachment,\n });\n }\n } catch (error) {\n if (this.previews.has(linkPreview.og_scrape_url)) {\n this.updatePreview(linkPreview.og_scrape_url, {\n status: LinkPreviewStatus.FAILED,\n });\n }\n }\n return linkPreview;\n }),\n );\n };\n\n cancelURLEnrichment = () => {\n this.findAndEnrichUrls.cancel();\n this.findAndEnrichUrls.flush();\n };\n\n /**\n * Clears all non-dismissed previews when the text composer is cleared.\n * This ensures that dismissed previews are not re-enriched in the future.\n */\n clearPreviews = () => {\n const currentPreviews = this.previews;\n const newPreviews = new Map<LinkURL, LinkPreview>();\n\n // Keep only dismissed previews\n currentPreviews.forEach((preview, url) => {\n if (LinkPreviewsManager.previewIsDismissed(preview)) {\n newPreviews.set(url, preview);\n }\n });\n\n this.state.partialNext({ previews: newPreviews });\n };\n\n updatePreview = (url: LinkURL, preview: Partial<LinkPreview>) => {\n if (!url) return;\n const existingPreview = this.previews.get(url);\n const status =\n preview.status ?? this.previews.get(url)?.status ?? LinkPreviewStatus.PENDING;\n let finalPreview = preview;\n if (existingPreview) {\n const merged = mergeWithDiff(existingPreview, preview);\n const isSame = !merged.diff || Object.keys(merged.diff).length === 0;\n if (isSame) return;\n finalPreview = merged.result;\n }\n this.state.partialNext({\n previews: new Map(this.previews).set(url, {\n ...finalPreview,\n og_scrape_url: url,\n status,\n }),\n });\n };\n\n dismissPreview = (url: LinkURL) => {\n const preview = this.previews.get(url);\n if (preview) {\n this.onLinkPreviewDismissed?.(preview);\n this.updatePreview(url, { status: LinkPreviewStatus.DISMISSED });\n }\n };\n\n static previewIsLoading = (preview: LinkPreview) =>\n preview.status === LinkPreviewStatus.LOADING;\n\n static previewIsLoaded = (preview: LinkPreview) =>\n preview.status === LinkPreviewStatus.LOADED;\n\n static previewIsDismissed = (preview: LinkPreview) =>\n preview.status === LinkPreviewStatus.DISMISSED;\n\n static previewIsFailed = (preview: LinkPreview) =>\n preview.status === LinkPreviewStatus.FAILED;\n\n static previewIsPending = (preview: LinkPreview) =>\n preview.status === LinkPreviewStatus.PENDING;\n\n static getPreviewData = (preview: LinkPreview) => {\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n const { status, ...data } = preview;\n return data;\n };\n}\n", "import { StateStore } from '../store';\nimport type { MessageComposer } from './messageComposer';\nimport type {\n DraftMessage,\n LiveLocationPayload,\n LocalMessage,\n StaticLocationPayload,\n} from '../types';\n\nexport type Coords = { latitude: number; longitude: number };\n\nexport type LocationComposerOptions = {\n composer: MessageComposer;\n message?: DraftMessage | LocalMessage;\n};\n\nexport type StaticLocationPreview = StaticLocationPayload;\n\nexport type LiveLocationPreview = Omit<LiveLocationPayload, 'end_at'> & {\n durationMs?: number;\n};\n\nexport type LocationComposerState = {\n location: StaticLocationPreview | LiveLocationPreview | null;\n};\n\nconst MIN_LIVE_LOCATION_SHARE_DURATION = 60 * 1000; // 1 minute;\n\nconst initState = ({\n message,\n}: {\n message?: DraftMessage | LocalMessage;\n}): LocationComposerState => ({\n location: message?.shared_location ?? null,\n});\n\nexport class LocationComposer {\n readonly state: StateStore<LocationComposerState>;\n readonly composer: MessageComposer;\n private _deviceId: string;\n\n constructor({ composer, message }: LocationComposerOptions) {\n this.composer = composer;\n this.state = new StateStore<LocationComposerState>(initState({ message }));\n this._deviceId = this.config.getDeviceId();\n }\n\n get config() {\n return this.composer.config.location;\n }\n\n get deviceId() {\n return this._deviceId;\n }\n\n get location() {\n return this.state.getLatestValue().location;\n }\n\n get validLocation(): StaticLocationPayload | LiveLocationPayload | null {\n const { durationMs, ...location } = (this.location ?? {}) as LiveLocationPreview;\n if (\n !!location?.created_by_device_id &&\n location.message_id &&\n location.latitude &&\n location.longitude &&\n (typeof durationMs === 'undefined' ||\n durationMs >= MIN_LIVE_LOCATION_SHARE_DURATION)\n ) {\n return {\n ...location,\n end_at: durationMs && new Date(Date.now() + durationMs).toISOString(),\n } as StaticLocationPayload | LiveLocationPayload;\n }\n return null;\n }\n\n initState = ({ message }: { message?: DraftMessage | LocalMessage } = {}) => {\n this.state.next(initState({ message }));\n };\n\n setData = (data: { durationMs?: number } & Coords) => {\n if (!this.config.enabled) return;\n if (!data.latitude || !data.longitude) return;\n\n this.state.partialNext({\n location: {\n ...data,\n message_id: this.composer.id,\n created_by_device_id: this.deviceId,\n },\n });\n };\n}\n", "import type { Middleware, MiddlewareHandlerParams } from '../../../middleware';\nimport { generateUUIDv4 } from '../../../utils';\nimport type {\n PollComposerFieldErrors,\n PollComposerState,\n PollComposerStateChangeMiddlewareValue,\n TargetedPollOptionTextUpdate,\n} from './types';\n\nexport const VALID_MAX_VOTES_VALUE_REGEX = /^([2-9]|10)$/;\n\nexport const MAX_POLL_OPTIONS = 100 as const;\n\nconst textFieldIsEmpty = (text: string) => !text.trim();\n\nexport type PollStateValidationOutput = Partial<\n Omit<Record<keyof PollComposerState['data'], string>, 'options'> & {\n options?: Record<string, string>;\n }\n>;\n\nexport type PollStateChangeValidator = (params: {\n data: PollComposerState['data'];\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n value: any;\n currentError?: PollComposerFieldErrors[keyof PollComposerFieldErrors];\n}) => PollStateValidationOutput;\n\nexport const pollStateChangeValidators: Partial<\n Record<keyof PollComposerState['data'], PollStateChangeValidator>\n> = {\n enforce_unique_vote: () => ({ max_votes_allowed: undefined }),\n max_votes_allowed: ({ data, value }) => {\n if (data.enforce_unique_vote && value)\n return { max_votes_allowed: 'Enforce unique vote is enabled' };\n const numericMatch = value.match(/^[0-9]+$/);\n if (!numericMatch && value) {\n return { max_votes_allowed: 'Only numbers are allowed' };\n }\n if (value?.length > 1 && !value.match(VALID_MAX_VOTES_VALUE_REGEX))\n return { max_votes_allowed: 'Type a number from 2 to 10' };\n return { max_votes_allowed: undefined };\n },\n options: ({ value: options }) => {\n const errors: Record<string, string> = {};\n const seenOptions = new Set<string>();\n\n options.forEach((option: { id: string; text: string }) => {\n if (seenOptions.has(option.text) && option.text.length) {\n errors[option.id] = 'Option already exists';\n } else {\n seenOptions.add(option.text);\n }\n });\n\n return Object.keys(errors).length > 0 ? { options: errors } : { options: undefined };\n },\n};\n\nexport const defaultPollFieldChangeEventValidators: Partial<\n Record<keyof PollComposerState['data'], PollStateChangeValidator>\n> = {\n name: ({ currentError, value }) =>\n value && currentError\n ? { name: undefined }\n : { name: typeof currentError === 'string' ? currentError : undefined },\n};\n\nexport const defaultPollFieldBlurEventValidators: Partial<\n Record<keyof PollComposerState['data'], PollStateChangeValidator>\n> = {\n max_votes_allowed: ({ value }) => {\n if (value && !value.match(VALID_MAX_VOTES_VALUE_REGEX))\n return { max_votes_allowed: 'Type a number from 2 to 10' };\n return { max_votes_allowed: undefined };\n },\n name: ({ value }) => {\n if (textFieldIsEmpty(value)) return { name: 'Question is required' };\n return { name: undefined };\n },\n options: (params) => {\n const defaultResult = pollStateChangeValidators.options?.(params);\n const errors = defaultResult?.options ?? {};\n params.value.forEach((option: { id: string; text: string }, index: number) => {\n const isTheLastOption = index === params.value.length - 1;\n if (textFieldIsEmpty(option.text) && !isTheLastOption) {\n errors[option.id] = 'Option is empty';\n }\n });\n return Object.keys(errors).length > 0 ? { options: errors } : { options: undefined };\n },\n};\n\nexport type PollCompositionStateProcessorOutput = Partial<PollComposerState['data']>;\n\nexport type PollCompositionStateProcessor = (params: {\n data: PollComposerState['data'];\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n value: any;\n}) => PollCompositionStateProcessorOutput;\n\nexport const isTargetedOptionTextUpdate = (\n value: unknown,\n): value is TargetedPollOptionTextUpdate =>\n !Array.isArray(value) &&\n typeof (value as TargetedPollOptionTextUpdate)?.index === 'number' &&\n typeof (value as TargetedPollOptionTextUpdate)?.text === 'string';\n\nexport const pollCompositionStateProcessors: Partial<\n Record<keyof PollComposerState['data'], PollCompositionStateProcessor>\n> = {\n enforce_unique_vote: ({ value }) => ({\n enforce_unique_vote: value,\n max_votes_allowed: '',\n }),\n options: ({ value, data }) => {\n // If it's a direct array update (like drag-drop reordering)\n if (Array.isArray(value)) {\n return {\n options: value.map((option) => ({\n id: option.id,\n text: option.text.trim(),\n })),\n };\n }\n\n // For single option updates\n const { index, text } = value;\n const prevOptions = data.options || [];\n\n const shouldRemoveOption =\n prevOptions && prevOptions.slice(index + 1).length > 0 && !text;\n\n const optionListHead = prevOptions.slice(0, index);\n const optionListTail = prevOptions.slice(index + 1);\n\n const newOptions = [\n ...optionListHead,\n ...(shouldRemoveOption ? [] : [{ ...prevOptions[index], text }]),\n ...optionListTail,\n ];\n\n const shouldAddNewOption =\n prevOptions.length < MAX_POLL_OPTIONS &&\n !newOptions.some((option) => !option.text.trim());\n\n if (shouldAddNewOption) {\n newOptions.push({ id: generateUUIDv4(), text: '' });\n }\n\n return { options: newOptions };\n },\n};\n\nexport type PollComposerStateMiddlewareFactoryOptions = {\n processors?: {\n handleFieldChange?: Partial<\n Record<keyof PollComposerState['data'], PollCompositionStateProcessor>\n >;\n handleFieldBlur?: Partial<\n Record<keyof PollComposerState['data'], PollCompositionStateProcessor>\n >;\n };\n validators?: {\n handleFieldChange?: Partial<\n Record<keyof PollComposerState['data'], PollStateChangeValidator>\n >;\n handleFieldBlur?: Partial<\n Record<keyof PollComposerState['data'], PollStateChangeValidator>\n >;\n };\n};\n\nexport type PollComposerStateMiddleware = Middleware<\n PollComposerStateChangeMiddlewareValue,\n 'handleFieldChange' | 'handleFieldBlur'\n>;\n\nexport const createPollComposerStateMiddleware = ({\n processors: customProcessors,\n validators: customValidators,\n}: PollComposerStateMiddlewareFactoryOptions = {}): PollComposerStateMiddleware => {\n const universalHandler = ({\n state,\n validators,\n processors,\n }: {\n state: PollComposerStateChangeMiddlewareValue;\n validators: Partial<\n Record<keyof PollComposerState['data'], PollStateChangeValidator>\n >;\n processors?: Partial<\n Record<keyof PollComposerState['data'], PollCompositionStateProcessor>\n >;\n }) => {\n const { previousState, targetFields } = state;\n\n let newData: Partial<PollComposerState['data']>;\n if (!processors && isTargetedOptionTextUpdate(targetFields.options)) {\n const options = [...previousState.data.options];\n const targetOption = previousState.data.options[targetFields.options.index];\n if (targetOption) {\n targetOption.text = targetFields.options.text;\n options.splice(targetFields.options.index, 1, targetOption);\n }\n newData = { ...targetFields, options };\n } else if (!processors) {\n newData = targetFields as PollComposerState['data'];\n } else {\n newData = Object.entries(targetFields).reduce(\n (acc, [key, value]) => {\n const processor = processors[key as keyof PollComposerState['data']];\n acc = {\n ...acc,\n ...(processor\n ? processor({ data: previousState.data, value })\n : { [key]: value }),\n };\n return acc;\n },\n {} as PollComposerState['data'],\n );\n }\n\n const newErrors = Object.keys(targetFields).reduce((acc, key) => {\n const validator = validators[key as keyof PollComposerState['data']];\n if (validator) {\n const error = validator({\n currentError: previousState.errors[key as keyof PollComposerState['data']],\n data: previousState.data,\n value: newData[key as keyof PollComposerState['data']],\n });\n acc = { ...acc, ...error };\n }\n return acc;\n }, {} as PollComposerFieldErrors);\n\n return { newData, newErrors };\n };\n\n return {\n id: 'stream-io/poll-composer-state-processing',\n handlers: {\n handleFieldChange: ({\n state,\n next,\n forward,\n }: MiddlewareHandlerParams<PollComposerStateChangeMiddlewareValue>) => {\n if (!state.targetFields) return forward();\n const { previousState, injectedFieldErrors } = state;\n\n const { newData, newErrors } = universalHandler({\n processors: {\n ...pollCompositionStateProcessors,\n ...customProcessors?.handleFieldChange,\n },\n state,\n validators: {\n ...pollStateChangeValidators,\n ...defaultPollFieldChangeEventValidators,\n ...customValidators?.handleFieldChange,\n },\n });\n\n return next({\n ...state,\n nextState: {\n ...previousState,\n data: { ...previousState.data, ...newData },\n errors: { ...previousState.errors, ...newErrors, ...injectedFieldErrors },\n },\n });\n },\n handleFieldBlur: ({\n state,\n next,\n forward,\n }: MiddlewareHandlerParams<PollComposerStateChangeMiddlewareValue>) => {\n if (!state.targetFields) return forward();\n\n const { previousState } = state;\n const { newData, newErrors } = universalHandler({\n processors: customProcessors?.handleFieldBlur,\n state,\n validators: {\n ...pollStateChangeValidators,\n ...defaultPollFieldBlurEventValidators,\n ...customValidators?.handleFieldBlur,\n },\n });\n\n return next({\n ...state,\n nextState: {\n ...previousState,\n data: { ...previousState.data, ...newData },\n errors: {\n ...previousState.errors,\n ...newErrors,\n ...state.injectedFieldErrors,\n },\n },\n });\n },\n },\n };\n};\n", "import type { Middleware, MiddlewareHandlerParams } from '../../../middleware';\nimport type { MessageComposer } from '../../messageComposer';\nimport type { PollComposerCompositionMiddlewareValueState } from './types';\n\nexport type PollCompositionValidationMiddleware = Middleware<\n PollComposerCompositionMiddlewareValueState,\n 'compose'\n>;\n\nexport const createPollCompositionValidationMiddleware = (\n composer: MessageComposer,\n): PollCompositionValidationMiddleware => ({\n id: 'stream-io/poll-composer-composition',\n handlers: {\n compose: ({\n discard,\n forward,\n }: MiddlewareHandlerParams<PollComposerCompositionMiddlewareValueState>) => {\n if (composer.pollComposer.canCreatePoll) return forward();\n return discard();\n },\n },\n});\n", "import { MiddlewareExecutor } from '../../../middleware';\nimport { createPollComposerStateMiddleware } from './state';\nimport { createPollCompositionValidationMiddleware } from './composition';\nimport type {\n PollComposerCompositionMiddlewareValueState,\n PollComposerStateChangeMiddlewareValue,\n} from './types';\nimport type { MessageComposer } from '../../messageComposer';\n\nexport type PollComposerMiddlewareExecutorOptions = {\n composer: MessageComposer;\n};\n\nexport class PollComposerCompositionMiddlewareExecutor extends MiddlewareExecutor<\n PollComposerCompositionMiddlewareValueState,\n 'compose'\n> {\n constructor({ composer }: PollComposerMiddlewareExecutorOptions) {\n super();\n this.use([createPollCompositionValidationMiddleware(composer)]);\n }\n}\n\nexport class PollComposerStateMiddlewareExecutor extends MiddlewareExecutor<\n PollComposerStateChangeMiddlewareValue,\n 'handleFieldChange' | 'handleFieldBlur'\n> {\n constructor() {\n super();\n this.use([createPollComposerStateMiddleware()]);\n }\n}\n", "import type { EVENT_MAP } from './events';\nimport type { Channel } from './channel';\nimport type { AxiosRequestConfig, AxiosResponse } from 'axios';\nimport type { StableWSConnection } from './connection';\nimport type { Role } from './permissions';\nimport type {\n CustomAttachmentData,\n CustomChannelData,\n CustomCommandData,\n CustomEventData,\n CustomMemberData,\n CustomMessageData,\n CustomPollData,\n CustomPollOptionData,\n CustomReactionData,\n CustomThreadData,\n CustomUserData,\n} from './custom_types';\nimport type { NotificationManager } from './notifications';\nimport type { RESERVED_UPDATED_MESSAGE_FIELDS } from './constants';\n\n/**\n * Utility Types\n */\n\nexport type Readable<T> = {\n [key in keyof T]: T[key];\n} & {};\n\nexport type ArrayOneOrMore<T> = {\n 0: T;\n} & Array<T>;\n\nexport type ArrayTwoOrMore<T> = {\n 0: T;\n 1: T;\n} & Array<T>;\n\nexport type KnownKeys<T> = {\n [K in keyof T]: string extends K ? never : number extends K ? never : K;\n} extends { [_ in keyof T]: infer U }\n ? U\n : never;\n\nexport type RequireAtLeastOne<T> = {\n [K in keyof T]-?: Required<Pick<T, K>> & Partial<Omit<T, K>>;\n}[keyof T];\n\nexport type RequireOnlyOne<T, Keys extends keyof T = keyof T> = Omit<T, Keys> &\n {\n [K in Keys]-?: Required<Pick<T, K>> & Partial<Record<Exclude<Keys, K>, undefined>>;\n }[Keys];\n\nexport type PartializeKeys<T, K extends keyof T> = Partial<Pick<T, K>> & Omit<T, K>;\n\n/* Unknown Record */\nexport type UR = Record<string, unknown>;\nexport type UnknownType = UR; //alias to avoid breaking change\n\nexport type Unpacked<T> = T extends (infer U)[]\n ? U // eslint-disable-next-line @typescript-eslint/no-explicit-any\n : T extends (...args: any[]) => infer U\n ? U\n : T extends Promise<infer U>\n ? U\n : T;\n\n/**\n * Response Types\n */\n\nexport type APIResponse = {\n duration: string;\n};\n\nexport type TranslateResponse = {\n language: string;\n translated_text: string;\n};\n\nexport type AppSettingsAPIResponse = APIResponse & {\n app?: {\n // TODO\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n call_types: any;\n channel_configs: Record<\n string,\n {\n reminders: boolean;\n automod?: ChannelConfigAutomod;\n automod_behavior?: ChannelConfigAutomodBehavior;\n automod_thresholds?: ChannelConfigAutomodThresholds;\n blocklist_behavior?: ChannelConfigAutomodBehavior;\n commands?: CommandVariants[];\n connect_events?: boolean;\n created_at?: string;\n custom_events?: boolean;\n mark_messages_pending?: boolean;\n max_message_length?: number;\n message_retention?: string;\n mutes?: boolean;\n name?: string;\n polls?: boolean;\n push_notifications?: boolean;\n quotes?: boolean;\n reactions?: boolean;\n read_events?: boolean;\n replies?: boolean;\n search?: boolean;\n typing_events?: boolean;\n updated_at?: string;\n uploads?: boolean;\n url_enrichment?: boolean;\n user_message_reminders?: boolean;\n }\n >;\n reminders_interval: number;\n async_moderation_config?: AsyncModerationOptions;\n async_url_enrich_enabled?: boolean;\n auto_translation_enabled?: boolean;\n before_message_send_hook_url?: string;\n campaign_enabled?: boolean;\n cdn_expiration_seconds?: number;\n custom_action_handler_url?: string;\n datadog_info?: {\n api_key: string;\n site: string;\n enabled?: boolean;\n };\n disable_auth_checks?: boolean;\n disable_permissions_checks?: boolean;\n enforce_unique_usernames?: 'no' | 'app' | 'team';\n event_hooks?: Array<EventHook>;\n file_upload_config?: FileUploadConfig;\n geofences?: Array<{\n country_codes: Array<string>;\n description: string;\n name: string;\n type: string;\n }>;\n grants?: Record<string, string[]>;\n image_moderation_enabled?: boolean;\n image_upload_config?: FileUploadConfig;\n multi_tenant_enabled?: boolean;\n name?: string;\n organization?: string;\n permission_version?: string;\n policies?: Record<string, Policy[]>;\n poll_enabled?: boolean;\n push_notifications?: {\n offline_only: boolean;\n version: string;\n apn?: APNConfig;\n firebase?: FirebaseConfig;\n huawei?: HuaweiConfig;\n providers?: PushProviderConfig[];\n xiaomi?: XiaomiConfig;\n };\n revoke_tokens_issued_before?: string | null;\n search_backend?: 'disabled' | 'elasticsearch' | 'postgres';\n sns_key?: string;\n sns_secret?: string;\n sns_topic_arn?: string;\n sqs_key?: string;\n sqs_secret?: string;\n sqs_url?: string;\n suspended?: boolean;\n suspended_explanation?: string;\n user_search_disallowed_roles?: string[] | null;\n video_provider?: string;\n webhook_events?: Array<string>;\n webhook_url?: string;\n };\n};\n\nexport type ModerationResult = {\n action: string;\n created_at: string;\n message_id: string;\n updated_at: string;\n user_bad_karma: boolean;\n user_karma: number;\n blocked_word?: string;\n blocklist_name?: string;\n moderated_by?: string;\n};\n\nexport type AutomodDetails = {\n action?: string;\n image_labels?: Array<string>;\n original_message_type?: string;\n result?: ModerationResult;\n};\n\nexport type FlagDetails = {\n automod?: AutomodDetails;\n};\n\nexport type Flag = {\n created_at: string;\n created_by_automod: boolean;\n updated_at: string;\n details?: FlagDetails;\n target_message?: MessageResponse;\n target_user?: UserResponse;\n user?: UserResponse;\n};\n\nexport type FlagsResponse = APIResponse & {\n flags?: Array<Flag>;\n};\n\nexport type MessageFlagsResponse = APIResponse & {\n flags?: Array<{\n message: MessageResponse;\n user: UserResponse;\n approved_at?: string;\n created_at?: string;\n created_by_automod?: boolean;\n moderation_result?: ModerationResult;\n rejected_at?: string;\n reviewed_at?: string;\n reviewed_by?: UserResponse;\n updated_at?: string;\n }>;\n};\n\nexport type FlagReport = {\n flags_count: number;\n id: string;\n message: MessageResponse;\n user: UserResponse;\n created_at?: string;\n details?: FlagDetails;\n first_reporter?: UserResponse;\n review_result?: string;\n reviewed_at?: string;\n reviewed_by?: UserResponse;\n updated_at?: string;\n};\n\nexport type FlagReportsResponse = APIResponse & {\n flag_reports: Array<FlagReport>;\n};\n\nexport type ReviewFlagReportResponse = APIResponse & {\n flag_report: FlagReport;\n};\n\nexport type BannedUsersResponse = APIResponse & {\n bans?: Array<{\n user: UserResponse;\n banned_by?: UserResponse;\n channel?: ChannelResponse;\n expires?: string;\n ip_ban?: boolean;\n reason?: string;\n timeout?: number;\n }>;\n};\n\nexport type BlockListResponse = BlockList & {\n created_at?: string;\n type?: string;\n updated_at?: string;\n};\n\nexport type ChannelResponse = CustomChannelData & {\n cid: string;\n disabled: boolean;\n frozen: boolean;\n id: string;\n type: string;\n blocked?: boolean;\n auto_translation_enabled?: boolean;\n auto_translation_language?: TranslationLanguages;\n hide_messages_before?: string;\n config?: ChannelConfigWithInfo;\n cooldown?: number;\n created_at?: string;\n created_by?: UserResponse | null;\n created_by_id?: string;\n deleted_at?: string;\n hidden?: boolean;\n invites?: string[];\n joined?: boolean;\n last_message_at?: string;\n member_count?: number;\n members?: ChannelMemberResponse[];\n message_count?: number;\n muted?: boolean;\n mute_expires_at?: string;\n own_capabilities?: string[];\n team?: string;\n truncated_at?: string;\n truncated_by?: UserResponse;\n truncated_by_id?: string;\n updated_at?: string;\n};\n\nexport type QueryReactionsOptions = Pager;\n\nexport type QueryReactionsAPIResponse = APIResponse & {\n reactions: ReactionResponse[];\n next?: string;\n};\n\nexport type QueryChannelsAPIResponse = APIResponse & {\n channels: Omit<ChannelAPIResponse, keyof APIResponse>[];\n};\n\nexport type QueryChannelAPIResponse = APIResponse & ChannelAPIResponse;\n\nexport type ChannelAPIResponse = {\n channel: ChannelResponse;\n members: ChannelMemberResponse[];\n messages: MessageResponse[];\n pinned_messages: MessageResponse[];\n draft?: DraftResponse;\n hidden?: boolean;\n membership?: ChannelMemberResponse | null;\n pending_messages?: PendingMessageResponse[];\n push_preferences?: PushPreference;\n read?: ReadResponse[];\n threads?: ThreadResponse[];\n watcher_count?: number;\n watchers?: UserResponse[];\n active_live_locations?: SharedLocationResponse[];\n};\n\nexport type ChannelUpdateOptions = {\n hide_history?: boolean;\n skip_push?: boolean;\n};\n\nexport type ChannelMemberAPIResponse = APIResponse & {\n members: ChannelMemberResponse[];\n};\n\nexport type ChannelMemberUpdates = CustomMemberData & {\n archived?: boolean;\n channel_role?: Role;\n pinned?: boolean;\n};\n\nexport type ChannelMemberResponse = CustomMemberData & {\n archived_at?: string | null;\n ban_expires?: string;\n banned?: boolean;\n channel_role?: Role;\n created_at?: string;\n invite_accepted_at?: string;\n invite_rejected_at?: string;\n invited?: boolean;\n is_moderator?: boolean;\n notifications_muted?: boolean;\n pinned_at?: string | null;\n role?: string;\n shadow_banned?: boolean;\n status?: InviteStatus;\n updated_at?: string;\n user?: UserResponse;\n user_id?: string;\n};\n\nexport type PartialUpdateMemberAPIResponse = APIResponse & {\n channel_member: ChannelMemberResponse;\n};\n\nexport type CheckPushResponse = APIResponse & {\n device_errors?: {\n [deviceID: string]: {\n error_message?: string;\n provider?: PushProvider;\n provider_name?: string;\n };\n };\n general_errors?: string[];\n rendered_apn_template?: string;\n rendered_firebase_template?: string;\n rendered_message?: {};\n skip_devices?: boolean;\n};\n\nexport type CheckSQSResponse = APIResponse & {\n status: string;\n data?: {};\n error?: string;\n};\n\nexport type CheckSNSResponse = APIResponse & {\n status: string;\n data?: {};\n error?: string;\n};\n\nexport type CommandResponse = Partial<CreatedAtUpdatedAt> & {\n args?: string;\n description?: string;\n name?: CommandVariants;\n set?: CommandVariants;\n};\n\nexport type ConnectAPIResponse = Promise<void | ConnectionOpen>;\n\nexport type CreateChannelResponse = APIResponse &\n Omit<CreateChannelOptions, 'client_id' | 'connection_id'> & {\n created_at: string;\n updated_at: string;\n grants?: Record<string, string[]>;\n };\n\nexport type CreateCommandResponse = APIResponse & {\n command: CreateCommandOptions & CreatedAtUpdatedAt;\n};\n\nexport type DeleteChannelAPIResponse = APIResponse & {\n channel: ChannelResponse;\n};\n\nexport type DeleteCommandResponse = APIResponse & {\n name?: CommandVariants;\n};\n\nexport type EventAPIResponse = APIResponse & {\n event: Event;\n};\n\nexport type ExportChannelResponse = {\n task_id: string;\n};\n\nexport type ExportUsersResponse = {\n task_id: string;\n};\n\nexport type ExportChannelStatusResponse = {\n created_at?: string;\n error?: {};\n result?: {};\n updated_at?: string;\n};\n\nexport type FlagMessageResponse = APIResponse & {\n flag: {\n created_at: string;\n created_by_automod: boolean;\n target_message_id: string;\n updated_at: string;\n user: UserResponse;\n approved_at?: string;\n channel_cid?: string;\n details?: object; // Any JSON\n message_user_id?: string;\n rejected_at?: string;\n reviewed_at?: string;\n reviewed_by?: string;\n };\n review_queue_item_id?: string;\n};\n\nexport type FlagUserResponse = APIResponse & {\n flag: {\n created_at: string;\n created_by_automod: boolean;\n target_user: UserResponse;\n updated_at: string;\n user: UserResponse;\n approved_at?: string;\n details?: object; // Any JSON\n rejected_at?: string;\n reviewed_at?: string;\n reviewed_by?: string;\n };\n review_queue_item_id?: string;\n};\n\nexport type LocalMessageBase = Omit<\n MessageResponseBase,\n 'created_at' | 'deleted_at' | 'pinned_at' | 'status' | 'updated_at'\n> & {\n created_at: Date;\n deleted_at: Date | null;\n pinned_at: Date | null;\n status: string;\n updated_at: Date;\n};\n\nexport type LocalMessage = LocalMessageBase & {\n error?: ErrorFromResponse<APIErrorResponse>;\n quoted_message?: LocalMessageBase;\n};\n\n/**\n * @deprecated in favor of LocalMessage\n */\nexport type FormatMessageResponse = LocalMessage;\n\nexport type GetCommandResponse = APIResponse & CreateCommandOptions & CreatedAtUpdatedAt;\n\nexport type GetMessageAPIResponse = SendMessageAPIResponse;\n\nexport interface ThreadResponse extends CustomThreadData {\n // FIXME: according to OpenAPI, `channel` could be undefined but since cid is provided I'll asume that it's wrong\n channel: ChannelResponse;\n channel_cid: string;\n created_at: string;\n created_by_user_id: string;\n latest_replies: Array<MessageResponse>;\n parent_message: MessageResponse;\n parent_message_id: string;\n title: string;\n updated_at: string;\n active_participant_count?: number;\n created_by?: UserResponse;\n deleted_at?: string;\n draft?: DraftResponse;\n last_message_at?: string;\n participant_count?: number;\n read?: Array<ReadResponse>;\n reply_count?: number;\n thread_participants?: Array<{\n channel_cid: string;\n created_at: string;\n last_read_at: string;\n last_thread_message_at?: string;\n left_thread_at?: string;\n thread_id?: string;\n user?: UserResponse;\n user_id?: string;\n }>;\n // TODO: when moving to API v2 we should do this instead\n // custom: CustomThreadType;\n}\n\n// TODO: Figure out a way to strongly type set and unset.\nexport type PartialThreadUpdate = {\n set?: Partial<Record<string, unknown>>;\n unset?: Array<string>;\n};\n\nexport type QueryThreadsOptions = {\n filter?: ThreadFilters;\n limit?: number;\n member_limit?: number;\n next?: string;\n participant_limit?: number;\n reply_limit?: number;\n sort?: ThreadSort;\n watch?: boolean;\n};\n\nexport type QueryThreadsAPIResponse = APIResponse & {\n threads: ThreadResponse[];\n next?: string;\n};\n\nexport type GetThreadOptions = {\n member_limit?: number;\n participant_limit?: number;\n reply_limit?: number;\n watch?: boolean;\n};\n\nexport type GetThreadAPIResponse = APIResponse & {\n thread: ThreadResponse;\n};\n\nexport type GetMultipleMessagesAPIResponse = APIResponse & {\n messages: MessageResponse[];\n};\n\nexport type GetRateLimitsResponse = APIResponse & {\n android?: RateLimitsMap;\n ios?: RateLimitsMap;\n server_side?: RateLimitsMap;\n web?: RateLimitsMap;\n};\n\nexport enum Product {\n Chat = 'chat',\n Video = 'video',\n Moderation = 'moderation',\n Feeds = 'feeds',\n}\n\nexport type HookEvent = {\n name: string;\n description: string;\n products: Product[];\n};\n\nexport type GetHookEventsResponse = APIResponse & {\n events: HookEvent[];\n};\n\nexport type GetReactionsAPIResponse = APIResponse & {\n reactions: ReactionResponse[];\n};\n\nexport type GetRepliesAPIResponse = APIResponse & {\n messages: MessageResponse[];\n};\n\nexport type GetUnreadCountAPIResponse = APIResponse & {\n channel_type: {\n channel_count: number;\n channel_type: string;\n unread_count: number;\n }[];\n channels: {\n channel_id: string;\n last_read: string;\n unread_count: number;\n }[];\n threads: {\n last_read: string;\n last_read_message_id: string;\n parent_message_id: string;\n unread_count: number;\n }[];\n total_unread_count: number;\n total_unread_threads_count: number;\n total_unread_count_by_team?: Record<string, number>;\n};\n\nexport type ChatLevelPushPreference = 'all' | 'none' | 'mentions' | (string & {});\n\nexport type PushPreference = {\n callLevel?: 'all' | 'none' | (string & {});\n chatLevel?: ChatLevelPushPreference;\n disabledUntil?: string; // snooze till this time\n removeDisable?: boolean; // Temporary flag for resetting disabledUntil\n};\n\nexport type ChannelPushPreference = {\n chatLevel?: ChatLevelPushPreference; // \"all\", \"none\", \"mentions\", or other custom strings\n disabledUntil?: string;\n removeDisable?: boolean; // Temporary flag for resetting disabledUntil\n};\n\nexport type UpsertPushPreferencesResponse = APIResponse & {\n // Mapping of user IDs to their push preferences\n userChannelPreferences: Record<string, Record<string, ChannelPushPreference>>;\n userPreferences: Record<string, PushPreference>; // Mapping of user -> channel id -> push preferences\n};\n\nexport type GetUnreadCountBatchAPIResponse = APIResponse & {\n counts_by_user: { [userId: string]: GetUnreadCountAPIResponse };\n};\n\nexport type ListChannelResponse = APIResponse & {\n channel_types: Record<\n string,\n Omit<CreateChannelOptions, 'client_id' | 'connection_id' | 'commands'> & {\n commands: CommandResponse[];\n created_at: string;\n updated_at: string;\n grants?: Record<string, string[]>;\n }\n >;\n};\n\nexport type ListChannelTypesAPIResponse = ListChannelResponse;\n\nexport type ListCommandsResponse = APIResponse & {\n commands: Array<CreateCommandOptions & Partial<CreatedAtUpdatedAt>>;\n};\n\nexport type MuteChannelAPIResponse = APIResponse & {\n channel_mute: ChannelMute;\n own_user: OwnUserResponse;\n channel_mutes?: ChannelMute[];\n mute?: MuteResponse;\n};\n\nexport type MessageResponse = MessageResponseBase & {\n quoted_message?: MessageResponseBase;\n};\n\nexport type MessageResponseBase = MessageBase & {\n type: MessageLabel;\n args?: string;\n before_message_send_failed?: boolean;\n channel?: ChannelResponse;\n cid?: string;\n command?: string;\n command_info?: { name?: string };\n created_at?: string;\n deleted_at?: string;\n deleted_reply_count?: number;\n i18n?: RequireAtLeastOne<Record<`${TranslationLanguages}_text`, string>> & {\n language: TranslationLanguages;\n };\n latest_reactions?: ReactionResponse[];\n member?: ChannelMemberResponse;\n mentioned_users?: UserResponse[];\n message_text_updated_at?: string;\n moderation?: ModerationResponse; // present only with Moderation v2\n moderation_details?: ModerationDetailsResponse; // present only with Moderation v1\n own_reactions?: ReactionResponse[] | null;\n pin_expires?: string | null;\n pinned_at?: string | null;\n pinned_by?: UserResponse | null;\n poll?: PollResponse;\n reaction_counts?: { [key: string]: number } | null;\n reaction_groups?: { [key: string]: ReactionGroupResponse } | null;\n reaction_scores?: { [key: string]: number } | null;\n reminder?: ReminderResponseBase;\n reply_count?: number;\n shadowed?: boolean;\n shared_location?: SharedLocationResponse;\n status?: string;\n thread_participants?: UserResponse[];\n updated_at?: string;\n};\n\nexport type ReactionGroupResponse = {\n count: number;\n sum_scores: number;\n first_reaction_at?: string;\n last_reaction_at?: string;\n};\n\nexport type ModerationDetailsResponse = {\n action: 'MESSAGE_RESPONSE_ACTION_BOUNCE' | (string & {});\n error_msg: string;\n harms: ModerationHarmResponse[];\n original_text: string;\n};\n\nexport type ModerationHarmResponse = {\n name: string;\n phrase_list_ids: number[];\n};\n\nexport type ModerationAction = 'bounce' | 'flag' | 'remove' | 'shadow';\n\nexport type ModerationResponse = {\n action: ModerationAction;\n original_text: string;\n};\n\nexport type MuteResponse = {\n user: UserResponse;\n created_at?: string;\n expires?: string;\n target?: UserResponse;\n updated_at?: string;\n};\n\nexport type MuteUserResponse = APIResponse & {\n mute?: MuteResponse;\n mutes?: Array<Mute>;\n own_user?: OwnUserResponse;\n};\n\nexport type BlockUserAPIResponse = APIResponse & {\n blocked_at: string;\n blocked_by_user_id: string;\n blocked_user_id: string;\n};\n\nexport type GetBlockedUsersAPIResponse = APIResponse & {\n blocks: BlockedUserDetails[];\n};\nexport type BlockedUserDetails = APIResponse & {\n blocked_user: UserResponse;\n blocked_user_id: string;\n created_at: string;\n user: UserResponse;\n user_id: string;\n};\n\nexport type OwnUserBase = {\n channel_mutes: ChannelMute[];\n devices: Device[];\n mutes: Mute[];\n total_unread_count: number;\n unread_channels: number;\n unread_count: number;\n unread_threads: number;\n invisible?: boolean;\n privacy_settings?: PrivacySettings;\n push_preferences?: PushPreference;\n roles?: string[];\n};\n\nexport type OwnUserResponse = UserResponse & OwnUserBase;\n\nexport type PartialUpdateChannelAPIResponse = APIResponse & {\n channel: ChannelResponse;\n members: ChannelMemberResponse[];\n};\n\nexport type PermissionAPIResponse = APIResponse & {\n permission?: PermissionAPIObject;\n};\n\nexport type PermissionsAPIResponse = APIResponse & {\n permissions?: PermissionAPIObject[];\n};\n\nexport type ReactionAPIResponse = APIResponse & {\n message: MessageResponse;\n reaction: ReactionResponse;\n};\n\nexport type ReactionResponse = Reaction & {\n created_at: string;\n message_id: string;\n updated_at: string;\n};\n\nexport type ReadResponse = {\n last_read: string;\n user: UserResponse;\n last_read_message_id?: string;\n unread_messages?: number;\n};\n\nexport type SearchAPIResponse = APIResponse & {\n results: {\n message: MessageResponse;\n }[];\n next?: string;\n previous?: string;\n results_warning?: SearchWarning | null;\n};\n\nexport type SearchWarning = {\n channel_search_cids: string[];\n channel_search_count: number;\n warning_code: number;\n warning_description: string;\n};\n\n// Thumb URL(thumb_url) is added considering video attachments as the backend will return the thumbnail in the response.\nexport type SendFileAPIResponse = APIResponse & { file: string; thumb_url?: string };\n\nexport type SendMessageAPIResponse = APIResponse & {\n message: MessageResponse;\n pending_message_metadata?: Record<string, string> | null;\n};\n\nexport type SyncResponse = APIResponse & {\n events: Event[];\n inaccessible_cids?: string[];\n};\n\nexport type TruncateChannelAPIResponse = APIResponse & {\n channel: ChannelResponse;\n message?: MessageResponse;\n};\n\nexport type UpdateChannelAPIResponse = APIResponse & {\n channel: ChannelResponse;\n members: ChannelMemberResponse[];\n message?: MessageResponse;\n};\n\nexport type UpdateChannelResponse = APIResponse &\n Omit<CreateChannelOptions, 'client_id' | 'connection_id'> & {\n created_at: string;\n updated_at: string;\n };\n\nexport type UpdateCommandResponse = APIResponse & {\n command: UpdateCommandOptions &\n CreatedAtUpdatedAt & {\n name: CommandVariants;\n };\n};\n\nexport type UpdateMessageAPIResponse = APIResponse & {\n message: MessageResponse;\n};\n\nexport type UsersAPIResponse = APIResponse & {\n users: Array<UserResponse>;\n};\n\nexport type UpdateUsersAPIResponse = APIResponse & {\n users: { [key: string]: UserResponse };\n};\n\nexport type UserResponse = CustomUserData & {\n id: string;\n anon?: boolean;\n banned?: boolean;\n blocked_user_ids?: string[];\n created_at?: string;\n deactivated_at?: string;\n deleted_at?: string;\n image?: string;\n language?: TranslationLanguages | '';\n last_active?: string;\n name?: string;\n notifications_muted?: boolean;\n online?: boolean;\n privacy_settings?: PrivacySettings;\n push_notifications?: PushNotificationSettings;\n revoke_tokens_issued_before?: string;\n role?: string;\n shadow_banned?: boolean;\n teams?: string[];\n teams_role?: TeamsRole;\n updated_at?: string;\n username?: string;\n avg_response_time?: number;\n};\n\nexport type TeamsRole = { [team: string]: string };\n\nexport type PrivacySettings = {\n read_receipts?: {\n enabled?: boolean;\n };\n typing_indicators?: {\n enabled?: boolean;\n };\n};\n\nexport type PushNotificationSettings = {\n disabled?: boolean;\n disabled_until?: string | null;\n};\n\n/**\n * Option Types\n */\n\nexport type MessageFlagsPaginationOptions = {\n limit?: number;\n offset?: number;\n};\n\nexport type FlagsPaginationOptions = {\n limit?: number;\n offset?: number;\n};\n\nexport type FlagReportsPaginationOptions = {\n limit?: number;\n offset?: number;\n};\n\nexport type ReviewFlagReportOptions = {\n review_details?: object;\n user_id?: string;\n};\n\nexport type BannedUsersPaginationOptions = Omit<\n PaginationOptions,\n 'id_gt' | 'id_gte' | 'id_lt' | 'id_lte'\n> & {\n exclude_expired_bans?: boolean;\n};\n\nexport type BanUserOptions = UnBanUserOptions & {\n banned_by?: UserResponse;\n banned_by_id?: string;\n ip_ban?: boolean;\n reason?: string;\n timeout?: number;\n delete_messages?: DeleteMessagesOptions;\n};\n\nexport type ChannelOptions = {\n limit?: number;\n member_limit?: number;\n message_limit?: number;\n offset?: number;\n presence?: boolean;\n state?: boolean;\n user_id?: string;\n watch?: boolean;\n};\n\nexport type ChannelQueryOptions = {\n client_id?: string;\n connection_id?: string;\n created_by?: UserResponse | null;\n created_by_id?: UserResponse['id'];\n data?: ChannelResponse;\n hide_for_creator?: boolean;\n members?: PaginationOptions;\n messages?: MessagePaginationOptions;\n presence?: boolean;\n state?: boolean;\n watch?: boolean;\n watchers?: PaginationOptions;\n};\n\nexport type ChannelStateOptions = {\n offlineMode?: boolean;\n skipInitialization?: string[];\n skipHydration?: boolean;\n};\n\nexport type CreateChannelOptions = {\n automod?: ChannelConfigAutomod;\n automod_behavior?: ChannelConfigAutomodBehavior;\n automod_thresholds?: ChannelConfigAutomodThresholds;\n blocklist?: string;\n blocklist_behavior?: ChannelConfigAutomodBehavior;\n client_id?: string;\n commands?: CommandVariants[];\n connect_events?: boolean;\n connection_id?: string;\n custom_events?: boolean;\n grants?: Record<string, string[]>;\n mark_messages_pending?: boolean;\n max_message_length?: number;\n message_retention?: string;\n mutes?: boolean;\n name?: string;\n permissions?: PermissionObject[];\n polls?: boolean;\n push_notifications?: boolean;\n quotes?: boolean;\n reactions?: boolean;\n read_events?: boolean;\n reminders?: boolean;\n replies?: boolean;\n search?: boolean;\n skip_last_msg_update_for_system_msgs?: boolean;\n typing_events?: boolean;\n uploads?: boolean;\n url_enrichment?: boolean;\n user_message_reminders?: boolean;\n};\n\nexport type CreateCommandOptions = {\n description: string;\n name: CommandVariants;\n args?: string;\n set?: CommandVariants;\n};\n\nexport type CustomPermissionOptions = {\n action: string;\n condition: object;\n id: string;\n name: string;\n description?: string;\n owner?: boolean;\n same_team?: boolean;\n};\n\nexport type DeactivateUsersOptions = {\n created_by_id?: string;\n mark_messages_deleted?: boolean;\n};\n\nexport type NewMemberPayload = CustomMemberData &\n Pick<ChannelMemberResponse, 'user_id' | 'channel_role'>;\n\nexport type Thresholds = Record<\n 'explicit' | 'spam' | 'toxic',\n Partial<{ block: number; flag: number }>\n>;\n\nexport type BlockListOptions = {\n behavior: BlocklistBehavior;\n blocklist: string;\n};\n\nexport type PolicyRequest = {\n action: 'Deny' | 'Allow' | (string & {});\n /**\n * @description User-friendly policy name\n */\n name: string;\n /**\n * @description Whether policy applies to resource owner or not\n */\n owner: boolean;\n priority: number;\n /**\n * @description List of resources to apply policy to\n */\n resources: string[];\n /**\n * @description List of roles to apply policy to\n */\n roles: string[];\n};\n\nexport type Automod = 'disabled' | 'simple' | 'AI' | (string & {});\nexport type AutomodBehavior = 'flag' | 'block' | 'shadow_block' | (string & {});\nexport type BlocklistBehavior = AutomodBehavior;\nexport type Command = {\n args: string;\n description: string;\n name: string;\n set: string;\n created_at?: string;\n updated_at?: string;\n};\n\nexport type UpdateChannelTypeRequest =\n // these three properties are required in OpenAPI spec but omitted in some QA tests\n Partial<{\n automod: Automod;\n automod_behavior: AutomodBehavior;\n max_message_length: number;\n }> & {\n allowed_flag_reasons?: string[];\n automod_thresholds?: Thresholds;\n blocklist?: string;\n blocklist_behavior?: BlocklistBehavior;\n blocklists?: BlockListOptions[];\n commands?: CommandVariants[];\n connect_events?: boolean;\n custom_events?: boolean;\n grants?: Record<string, string[]>;\n mark_messages_pending?: boolean;\n mutes?: boolean;\n partition_size?: number;\n /**\n * @example 24h\n */\n partition_ttl?: string | null;\n permissions?: PolicyRequest[];\n polls?: boolean;\n push_notifications?: boolean;\n quotes?: boolean;\n reactions?: boolean;\n read_events?: boolean;\n reminders?: boolean;\n replies?: boolean;\n search?: boolean;\n skip_last_msg_update_for_system_msgs?: boolean;\n typing_events?: boolean;\n uploads?: boolean;\n url_enrichment?: boolean;\n };\n\nexport type UpdateChannelTypeResponse = {\n automod: Automod;\n automod_behavior: AutomodBehavior;\n commands: CommandVariants[];\n connect_events: boolean;\n created_at: string;\n custom_events: boolean;\n duration: string;\n grants: Record<string, string[]>;\n mark_messages_pending: boolean;\n max_message_length: number;\n mutes: boolean;\n name: string;\n permissions: PolicyRequest[];\n polls: boolean;\n push_notifications: boolean;\n quotes: boolean;\n reactions: boolean;\n read_events: boolean;\n reminders: boolean;\n replies: boolean;\n search: boolean;\n skip_last_msg_update_for_system_msgs: boolean;\n typing_events: boolean;\n updated_at: string;\n uploads: boolean;\n url_enrichment: boolean;\n allowed_flag_reasons?: string[];\n automod_thresholds?: Thresholds;\n blocklist?: string;\n blocklist_behavior?: BlocklistBehavior;\n blocklists?: BlockListOptions[];\n partition_size?: number;\n partition_ttl?: string;\n};\n\nexport type GetChannelTypeResponse = {\n automod: Automod;\n automod_behavior: AutomodBehavior;\n commands: Command[];\n connect_events: boolean;\n created_at: string;\n custom_events: boolean;\n duration: string;\n grants: Record<string, string[]>;\n mark_messages_pending: boolean;\n max_message_length: number;\n mutes: boolean;\n name: string;\n permissions: PolicyRequest[];\n polls: boolean;\n push_notifications: boolean;\n quotes: boolean;\n reactions: boolean;\n read_events: boolean;\n reminders: boolean;\n replies: boolean;\n search: boolean;\n skip_last_msg_update_for_system_msgs: boolean;\n typing_events: boolean;\n updated_at: string;\n uploads: boolean;\n url_enrichment: boolean;\n allowed_flag_reasons?: string[];\n automod_thresholds?: Thresholds;\n blocklist?: string;\n blocklist_behavior?: BlocklistBehavior;\n blocklists?: BlockListOptions[];\n partition_size?: number;\n partition_ttl?: string;\n};\n\nexport type UpdateChannelOptions = Partial<{\n accept_invite: boolean;\n add_members: string[];\n add_moderators: string[];\n client_id: string;\n connection_id: string;\n data: Omit<ChannelResponse, 'id' | 'cid'>;\n demote_moderators: string[];\n invites: string[];\n message: MessageResponse;\n reject_invite: boolean;\n remove_members: string[];\n user: UserResponse;\n user_id: string;\n}>;\n\nexport type MarkChannelsReadOptions = {\n client_id?: string;\n connection_id?: string;\n read_by_channel?: Record<string, string>;\n user?: UserResponse;\n user_id?: string;\n};\n\nexport type MarkReadOptions = {\n client_id?: string;\n connection_id?: string;\n thread_id?: string;\n user?: UserResponse;\n user_id?: string;\n};\n\nexport type MarkUnreadOptions = {\n client_id?: string;\n connection_id?: string;\n message_id?: string;\n thread_id?: string;\n user?: UserResponse;\n user_id?: string;\n};\n\nexport type MuteUserOptions = {\n client_id?: string;\n connection_id?: string;\n id?: string;\n reason?: string;\n target_user_id?: string;\n timeout?: number;\n type?: string;\n user?: UserResponse;\n user_id?: string;\n};\n\nexport type PaginationOptions = {\n created_at_after?: string | Date;\n created_at_after_or_equal?: string | Date;\n created_at_before?: string | Date;\n created_at_before_or_equal?: string | Date;\n id_gt?: string;\n id_gte?: string;\n id_lt?: string;\n id_lte?: string;\n limit?: number;\n offset?: number; // should be avoided with channel.query()\n};\n\nexport type MessagePaginationOptions = PaginationOptions & {\n created_at_around?: string | Date;\n id_around?: string;\n};\n\nexport type PinnedMessagePaginationOptions = {\n id_around?: string;\n id_gt?: string;\n id_gte?: string;\n id_lt?: string;\n id_lte?: string;\n limit?: number;\n offset?: number;\n pinned_at_after?: string | Date;\n pinned_at_after_or_equal?: string | Date;\n pinned_at_around?: string | Date;\n pinned_at_before?: string | Date;\n pinned_at_before_or_equal?: string | Date;\n};\n\nexport type QueryMembersOptions = {\n // Pagination option: select members created after the date (RFC399)\n created_at_after?: string;\n // Pagination option: select members created after or equal the date (RFC399)\n created_at_after_or_equal?: string;\n // Pagination option: select members created before the date (RFC399)\n created_at_before?: string;\n // Pagination option: select members created before or equal the date (RFC399)\n created_at_before_or_equal?: string;\n // Number of members to return, default 100\n limit?: number;\n // Offset (max is 1000)\n offset?: number;\n // \tPagination option: excludes members with ID less or equal the value\n user_id_gt?: string;\n // Pagination option: excludes members with ID less than the value\n user_id_gte?: string;\n // Pagination option: excludes members with ID greater or equal the value\n user_id_lt?: string;\n // \tPagination option: excludes members with ID greater than the value\n user_id_lte?: string;\n};\n\nexport type ReactivateUserOptions = {\n created_by_id?: string;\n name?: string;\n restore_messages?: boolean;\n};\n\nexport type ReactivateUsersOptions = {\n created_by_id?: string;\n restore_messages?: boolean;\n};\n\nexport type SearchOptions = {\n limit?: number;\n next?: string;\n offset?: number;\n sort?: SearchMessageSort;\n};\n\nexport type StreamChatOptions = AxiosRequestConfig & {\n /**\n * Used to disable warnings that are triggered by using connectUser or connectAnonymousUser server-side.\n */\n allowServerSideConnect?: boolean;\n axiosRequestConfig?: AxiosRequestConfig;\n /**\n * Base url to use for API\n * such as https://chat-proxy-dublin.stream-io-api.com\n */\n baseURL?: string;\n browser?: boolean;\n device?: BaseDeviceFields;\n /**\n * Disables the hydration of all caches within the JS Client. This includes this.activeChannels,\n * this.polls.pollCache and this.config.\n * It is mainly meant to be used for integrations where stream-chat is used as a server-side service\n * interacting with Stream's REST API, not depending on any state and purely serving as a wrapper\n * around HTTP requests. Using this property on either the client side or a backend implementation\n * that also relies on WS events will break these functionalities, so please use carefully.\n */\n disableCache?: boolean;\n enableInsights?: boolean;\n /** experimental feature, please contact support if you want this feature enabled for you */\n enableWSFallback?: boolean;\n logger?: Logger;\n /**\n * Custom notification manager service to use for the client.\n * If not provided, a default notification manager will be created.\n * Notifications are used to communicate events like errors, warnings, info, etc. Other services can publish notifications or subscribe to the NotificationManager state changes.\n */\n notifications?: NotificationManager;\n /**\n * When true, user will be persisted on client. Otherwise if `connectUser` call fails, then you need to\n * call `connectUser` again to retry.\n * This is mainly useful for chat application working in offline mode, where you will need client.user to\n * persist even if connectUser call fails.\n */\n persistUserOnConnectionFailure?: boolean;\n /**\n * When network is recovered, we re-query the active channels on client. But in single query, you can recover\n * only 30 channels. So its not guaranteed that all the channels in activeChannels object have updated state.\n * Thus in UI sdks, state recovery is managed by components themselves, they don't rely on js client for this.\n *\n * `recoverStateOnReconnect` parameter can be used in such cases, to disable state recovery within js client.\n * When false, user/consumer of this client will need to make sure all the channels present on UI by\n * manually calling queryChannels endpoint.\n */\n recoverStateOnReconnect?: boolean;\n warmUp?: boolean;\n /**\n * Set the instance of StableWSConnection on chat client. Its purely for testing purpose and should\n * not be used in production apps.\n */\n wsConnection?: StableWSConnection;\n /**\n * Sets a suffix to the wsUrl when it is being built in `wsConnection`. Is meant to be\n * used purely in testing suites and should not be used in production apps.\n */\n wsUrlParams?: URLSearchParams;\n};\n\nexport type SyncOptions = {\n /**\n * This will behave as queryChannels option.\n */\n watch?: boolean;\n /**\n * Return channels from request that user does not have access to in a separate\n * field in the response called 'inaccessible_cids' instead of\n * adding them as 'notification.removed_from_channel' events.\n */\n with_inaccessible_cids?: boolean;\n};\n\nexport type UnBanUserOptions = {\n client_id?: string;\n connection_id?: string;\n id?: string;\n shadow?: boolean;\n target_user_id?: string;\n type?: string;\n};\n\nexport type UpdateCommandOptions = {\n description: string;\n args?: string;\n set?: CommandVariants;\n};\n\nexport type UserOptions = {\n include_deactivated_users?: boolean;\n limit?: number;\n offset?: number;\n presence?: boolean;\n};\n\n/**\n * Event Types\n */\n\nexport type ConnectionChangeEvent = {\n type: EventTypes;\n online?: boolean;\n};\n\nexport type Event = CustomEventData & {\n type: EventTypes;\n ai_message?: string;\n ai_state?: AIState;\n channel?: ChannelResponse;\n channel_custom?: CustomChannelData;\n channel_member_count?: number;\n channel_id?: string;\n channel_type?: string;\n cid?: string;\n clear_history?: boolean;\n connection_id?: string;\n // event creation timestamp, format Date ISO string\n created_at?: string;\n draft?: DraftResponse;\n // id of the message that was marked as unread - all the following messages are considered unread. (notification.mark_unread)\n first_unread_message_id?: string;\n hard_delete?: boolean;\n // creation date of a message with last_read_message_id, formatted as Date ISO string\n last_read_at?: string;\n last_read_message_id?: string;\n live_location?: SharedLocationResponse;\n mark_messages_deleted?: boolean;\n me?: OwnUserResponse;\n member?: ChannelMemberResponse;\n message?: MessageResponse;\n message_id?: string;\n mode?: string;\n online?: boolean;\n own_capabilities?: string[];\n parent_id?: string;\n poll?: PollResponse;\n poll_vote?: PollVote | PollAnswer;\n queriedChannels?: {\n channels: ChannelAPIResponse[];\n isLatestMessageSet?: boolean;\n };\n offlineReactions?: ReactionResponse[];\n reaction?: ReactionResponse;\n received_at?: string | Date;\n reminder?: ReminderResponse;\n shadow?: boolean;\n team?: string;\n thread?: ThreadResponse;\n // @deprecated number of all unread messages across all current user's unread channels, equals unread_count\n total_unread_count?: number;\n // number of all current user's channels with at least one unread message including the channel in this event\n unread_channels?: number;\n // number of all unread messages across all current user's unread channels\n unread_count?: number;\n // number of unread messages in the channel from this event (notification.mark_unread)\n unread_messages?: number;\n unread_thread_messages?: number;\n unread_threads?: number;\n user?: UserResponse;\n user_id?: string;\n watcher_count?: number;\n channel_last_message_at?: string;\n app?: Record<string, unknown>; // TODO: further specify type\n};\n\nexport type UserCustomEvent = CustomEventData & {\n type: string;\n};\n\nexport type EventHandler = (event: Event) => void;\n\nexport type EventTypes = 'all' | keyof typeof EVENT_MAP;\n\n/**\n * Filter Types\n */\n\nexport type AscDesc = 1 | -1;\n\nexport type MessageFlagsFiltersOptions = {\n channel_cid?: string;\n is_reviewed?: boolean;\n team?: string;\n user_id?: string;\n};\n\nexport type MessageFlagsFilters = QueryFilters<\n {\n channel_cid?:\n | RequireOnlyOne<\n Pick<QueryFilter<MessageFlagsFiltersOptions['channel_cid']>, '$eq' | '$in'>\n >\n | PrimitiveFilter<MessageFlagsFiltersOptions['channel_cid']>;\n } & {\n team?:\n | RequireOnlyOne<\n Pick<QueryFilter<MessageFlagsFiltersOptions['team']>, '$eq' | '$in'>\n >\n | PrimitiveFilter<MessageFlagsFiltersOptions['team']>;\n } & {\n user_id?:\n | RequireOnlyOne<\n Pick<QueryFilter<MessageFlagsFiltersOptions['user_id']>, '$eq' | '$in'>\n >\n | PrimitiveFilter<MessageFlagsFiltersOptions['user_id']>;\n } & {\n [Key in keyof Omit<\n MessageFlagsFiltersOptions,\n 'channel_cid' | 'user_id' | 'is_reviewed'\n >]:\n | RequireOnlyOne<QueryFilter<MessageFlagsFiltersOptions[Key]>>\n | PrimitiveFilter<MessageFlagsFiltersOptions[Key]>;\n }\n>;\n\nexport type FlagsFiltersOptions = {\n channel_cid?: string;\n message_id?: string;\n message_user_id?: string;\n reporter_id?: string;\n team?: string;\n user_id?: string;\n};\n\nexport type FlagsFilters = QueryFilters<\n {\n user_id?:\n | RequireOnlyOne<Pick<QueryFilter<FlagsFiltersOptions['user_id']>, '$eq' | '$in'>>\n | PrimitiveFilter<FlagsFiltersOptions['user_id']>;\n } & {\n message_id?:\n | RequireOnlyOne<\n Pick<QueryFilter<FlagsFiltersOptions['message_id']>, '$eq' | '$in'>\n >\n | PrimitiveFilter<FlagsFiltersOptions['message_id']>;\n } & {\n message_user_id?:\n | RequireOnlyOne<\n Pick<QueryFilter<FlagsFiltersOptions['message_user_id']>, '$eq' | '$in'>\n >\n | PrimitiveFilter<FlagsFiltersOptions['message_user_id']>;\n } & {\n channel_cid?:\n | RequireOnlyOne<\n Pick<QueryFilter<FlagsFiltersOptions['channel_cid']>, '$eq' | '$in'>\n >\n | PrimitiveFilter<FlagsFiltersOptions['channel_cid']>;\n } & {\n reporter_id?:\n | RequireOnlyOne<\n Pick<QueryFilter<FlagsFiltersOptions['reporter_id']>, '$eq' | '$in'>\n >\n | PrimitiveFilter<FlagsFiltersOptions['reporter_id']>;\n } & {\n team?:\n | RequireOnlyOne<Pick<QueryFilter<FlagsFiltersOptions['team']>, '$eq' | '$in'>>\n | PrimitiveFilter<FlagsFiltersOptions['team']>;\n }\n>;\n\nexport type FlagReportsFiltersOptions = {\n channel_cid?: string;\n is_reviewed?: boolean;\n message_id?: string;\n message_user_id?: string;\n report_id?: string;\n review_result?: string;\n reviewed_by?: string;\n team?: string;\n user_id?: string;\n};\n\nexport type FlagReportsFilters = QueryFilters<\n {\n report_id?:\n | RequireOnlyOne<\n Pick<QueryFilter<FlagReportsFiltersOptions['report_id']>, '$eq' | '$in'>\n >\n | PrimitiveFilter<FlagReportsFiltersOptions['report_id']>;\n } & {\n review_result?:\n | RequireOnlyOne<\n Pick<QueryFilter<FlagReportsFiltersOptions['review_result']>, '$eq' | '$in'>\n >\n | PrimitiveFilter<FlagReportsFiltersOptions['review_result']>;\n } & {\n reviewed_by?:\n | RequireOnlyOne<\n Pick<QueryFilter<FlagReportsFiltersOptions['reviewed_by']>, '$eq' | '$in'>\n >\n | PrimitiveFilter<FlagReportsFiltersOptions['reviewed_by']>;\n } & {\n user_id?:\n | RequireOnlyOne<\n Pick<QueryFilter<FlagReportsFiltersOptions['user_id']>, '$eq' | '$in'>\n >\n | PrimitiveFilter<FlagReportsFiltersOptions['user_id']>;\n } & {\n message_id?:\n | RequireOnlyOne<\n Pick<QueryFilter<FlagReportsFiltersOptions['message_id']>, '$eq' | '$in'>\n >\n | PrimitiveFilter<FlagReportsFiltersOptions['message_id']>;\n } & {\n message_user_id?:\n | RequireOnlyOne<\n Pick<QueryFilter<FlagReportsFiltersOptions['message_user_id']>, '$eq' | '$in'>\n >\n | PrimitiveFilter<FlagReportsFiltersOptions['message_user_id']>;\n } & {\n channel_cid?:\n | RequireOnlyOne<\n Pick<QueryFilter<FlagReportsFiltersOptions['channel_cid']>, '$eq' | '$in'>\n >\n | PrimitiveFilter<FlagReportsFiltersOptions['channel_cid']>;\n } & {\n team?:\n | RequireOnlyOne<\n Pick<QueryFilter<FlagReportsFiltersOptions['team']>, '$eq' | '$in'>\n >\n | PrimitiveFilter<FlagReportsFiltersOptions['team']>;\n } & {\n [Key in keyof Omit<\n FlagReportsFiltersOptions,\n 'report_id' | 'user_id' | 'message_id' | 'review_result' | 'reviewed_by'\n >]:\n | RequireOnlyOne<QueryFilter<FlagReportsFiltersOptions[Key]>>\n | PrimitiveFilter<FlagReportsFiltersOptions[Key]>;\n }\n>;\n\nexport type BannedUsersFilterOptions = {\n banned_by_id?: string;\n channel_cid?: string;\n created_at?: string;\n reason?: string;\n user_id?: string;\n};\n\nexport type BannedUsersFilters = QueryFilters<\n {\n channel_cid?:\n | RequireOnlyOne<\n Pick<QueryFilter<BannedUsersFilterOptions['channel_cid']>, '$eq' | '$in'>\n >\n | PrimitiveFilter<BannedUsersFilterOptions['channel_cid']>;\n } & {\n reason?:\n | RequireOnlyOne<\n {\n $autocomplete?: BannedUsersFilterOptions['reason'];\n } & QueryFilter<BannedUsersFilterOptions['reason']>\n >\n | PrimitiveFilter<BannedUsersFilterOptions['reason']>;\n } & {\n [Key in keyof Omit<BannedUsersFilterOptions, 'channel_cid' | 'reason'>]:\n | RequireOnlyOne<QueryFilter<BannedUsersFilterOptions[Key]>>\n | PrimitiveFilter<BannedUsersFilterOptions[Key]>;\n }\n>;\n\nexport type ReactionFilters = QueryFilters<\n {\n user_id?:\n | RequireOnlyOne<Pick<QueryFilter<ReactionResponse['user_id']>, '$eq' | '$in'>>\n | PrimitiveFilter<ReactionResponse['user_id']>;\n } & {\n type?:\n | RequireOnlyOne<Pick<QueryFilter<ReactionResponse['type']>, '$eq'>>\n | PrimitiveFilter<ReactionResponse['type']>;\n } & {\n created_at?:\n | RequireOnlyOne<\n Pick<\n QueryFilter<PollResponse['created_at']>,\n '$eq' | '$gt' | '$lt' | '$gte' | '$lte'\n >\n >\n | PrimitiveFilter<PollResponse['created_at']>;\n }\n>;\n\nexport type ChannelFilters = QueryFilters<\n ContainsOperator<Omit<CustomChannelData, 'name'>> & {\n archived?: boolean;\n 'member.user.name'?:\n | RequireOnlyOne<{\n $autocomplete?: string;\n $eq?: string;\n }>\n | string;\n\n members?:\n | RequireOnlyOne<Pick<QueryFilter<string>, '$in'>>\n | RequireOnlyOne<Pick<QueryFilter<string[]>, '$eq'>>\n | PrimitiveFilter<string[]>;\n name?:\n | RequireOnlyOne<\n {\n $autocomplete?: string;\n } & QueryFilter<string>\n >\n | PrimitiveFilter<string>;\n pinned?: boolean;\n last_updated?:\n | RequireOnlyOne<Pick<QueryFilter<string>, '$eq' | '$gt' | '$gte' | '$lt' | '$lte'>>\n | PrimitiveFilter<string>;\n } & {\n [Key in keyof Omit<ChannelResponse, 'name' | 'members' | keyof CustomChannelData>]:\n | RequireOnlyOne<QueryFilter<ChannelResponse[Key]>>\n | PrimitiveFilter<ChannelResponse[Key]>;\n }\n>;\n\nexport type DraftFilters = {\n channel_cid?:\n | RequireOnlyOne<Pick<QueryFilter<DraftResponse['channel_cid']>, '$in' | '$eq'>>\n | PrimitiveFilter<DraftResponse['channel_cid']>;\n created_at?:\n | RequireOnlyOne<\n Pick<\n QueryFilter<DraftResponse['created_at']>,\n '$eq' | '$gt' | '$lt' | '$gte' | '$lte'\n >\n >\n | PrimitiveFilter<DraftResponse['created_at']>;\n parent_id?:\n | RequireOnlyOne<\n Pick<QueryFilter<DraftResponse['created_at']>, '$in' | '$eq' | '$exists'>\n >\n | PrimitiveFilter<DraftResponse['parent_id']>;\n};\n\nexport type QueryPollsParams = {\n filter?: QueryPollsFilters;\n options?: QueryPollsOptions;\n sort?: PollSort;\n};\n\nexport type QueryPollsOptions = Pager;\n\nexport type VotesFiltersOptions = {\n is_answer?: boolean;\n option_id?: string;\n user_id?: string;\n};\n\nexport type QueryVotesOptions = Pager;\n\nexport type QueryPollsFilters = QueryFilters<\n {\n id?:\n | RequireOnlyOne<Pick<QueryFilter<PollResponse['id']>, '$eq' | '$in'>>\n | PrimitiveFilter<PollResponse['id']>;\n } & {\n user_id?:\n | RequireOnlyOne<Pick<QueryFilter<VotesFiltersOptions['user_id']>, '$eq' | '$in'>>\n | PrimitiveFilter<VotesFiltersOptions['user_id']>;\n } & {\n is_closed?:\n | RequireOnlyOne<Pick<QueryFilter<PollResponse['is_closed']>, '$eq'>>\n | PrimitiveFilter<PollResponse['is_closed']>;\n } & {\n max_votes_allowed?:\n | RequireOnlyOne<\n Pick<\n QueryFilter<PollResponse['max_votes_allowed']>,\n '$eq' | '$gt' | '$lt' | '$gte' | '$lte'\n >\n >\n | PrimitiveFilter<PollResponse['max_votes_allowed']>;\n } & {\n allow_answers?:\n | RequireOnlyOne<Pick<QueryFilter<PollResponse['allow_answers']>, '$eq'>>\n | PrimitiveFilter<PollResponse['allow_answers']>;\n } & {\n allow_user_suggested_options?:\n | RequireOnlyOne<\n Pick<QueryFilter<PollResponse['allow_user_suggested_options']>, '$eq'>\n >\n | PrimitiveFilter<PollResponse['allow_user_suggested_options']>;\n } & {\n voting_visibility?:\n | RequireOnlyOne<Pick<QueryFilter<PollResponse['voting_visibility']>, '$eq'>>\n | PrimitiveFilter<PollResponse['voting_visibility']>;\n } & {\n created_at?:\n | RequireOnlyOne<\n Pick<\n QueryFilter<PollResponse['created_at']>,\n '$eq' | '$gt' | '$lt' | '$gte' | '$lte'\n >\n >\n | PrimitiveFilter<PollResponse['created_at']>;\n } & {\n created_by_id?:\n | RequireOnlyOne<Pick<QueryFilter<PollResponse['created_by_id']>, '$eq' | '$in'>>\n | PrimitiveFilter<PollResponse['created_by_id']>;\n } & {\n updated_at?:\n | RequireOnlyOne<\n Pick<\n QueryFilter<PollResponse['updated_at']>,\n '$eq' | '$gt' | '$lt' | '$gte' | '$lte'\n >\n >\n | PrimitiveFilter<PollResponse['updated_at']>;\n } & {\n name?:\n | RequireOnlyOne<Pick<QueryFilter<PollResponse['name']>, '$eq' | '$in'>>\n | PrimitiveFilter<PollResponse['name']>;\n }\n>;\n\nexport type QueryVotesFilters = QueryFilters<\n {\n id?:\n | RequireOnlyOne<Pick<QueryFilter<PollResponse['id']>, '$eq' | '$in'>>\n | PrimitiveFilter<PollResponse['id']>;\n } & {\n option_id?:\n | RequireOnlyOne<Pick<QueryFilter<VotesFiltersOptions['option_id']>, '$eq' | '$in'>>\n | PrimitiveFilter<VotesFiltersOptions['option_id']>;\n } & {\n is_answer?:\n | RequireOnlyOne<Pick<QueryFilter<VotesFiltersOptions['is_answer']>, '$eq'>>\n | PrimitiveFilter<VotesFiltersOptions['is_answer']>;\n } & {\n user_id?:\n | RequireOnlyOne<Pick<QueryFilter<VotesFiltersOptions['user_id']>, '$eq' | '$in'>>\n | PrimitiveFilter<VotesFiltersOptions['user_id']>;\n } & {\n created_at?:\n | RequireOnlyOne<\n Pick<\n QueryFilter<PollResponse['created_at']>,\n '$eq' | '$gt' | '$lt' | '$gte' | '$lte'\n >\n >\n | PrimitiveFilter<PollResponse['created_at']>;\n } & {\n created_by_id?:\n | RequireOnlyOne<Pick<QueryFilter<PollResponse['created_by_id']>, '$eq' | '$in'>>\n | PrimitiveFilter<PollResponse['created_by_id']>;\n } & {\n updated_at?:\n | RequireOnlyOne<\n Pick<\n QueryFilter<PollResponse['updated_at']>,\n '$eq' | '$gt' | '$lt' | '$gte' | '$lte'\n >\n >\n | PrimitiveFilter<PollResponse['updated_at']>;\n }\n>;\n\nexport type ContainsOperator<CustomType = {}> = {\n [Key in keyof CustomType]?: CustomType[Key] extends (infer ContainType)[]\n ?\n | RequireOnlyOne<\n {\n $contains?: ContainType extends object\n ? PrimitiveFilter<RequireAtLeastOne<ContainType>>\n : PrimitiveFilter<ContainType>;\n } & QueryFilter<PrimitiveFilter<ContainType>[]>\n >\n | PrimitiveFilter<PrimitiveFilter<ContainType>[]>\n : RequireOnlyOne<QueryFilter<CustomType[Key]>> | PrimitiveFilter<CustomType[Key]>;\n};\n\nexport type MessageFilters = QueryFilters<\n ContainsOperator<CustomMessageData> & {\n 'attachments.type'?:\n | RequireOnlyOne<{\n $eq: PrimitiveFilter<Attachment['type']>;\n $in: PrimitiveFilter<Attachment['type']>[];\n }>\n | PrimitiveFilter<Attachment['type']>;\n 'mentioned_users.id'?: RequireOnlyOne<{\n $contains: PrimitiveFilter<UserResponse['id']>;\n }>;\n text?:\n | RequireOnlyOne<\n {\n $autocomplete?: MessageResponse['text'];\n $q?: MessageResponse['text'];\n } & QueryFilter<MessageResponse['text']>\n >\n | PrimitiveFilter<MessageResponse['text']>;\n 'user.id'?:\n | RequireOnlyOne<\n {\n $autocomplete?: UserResponse['id'];\n } & QueryFilter<UserResponse['id']>\n >\n | PrimitiveFilter<UserResponse['id']>;\n } & {\n [Key in keyof Omit<MessageResponse, 'text' | keyof CustomMessageData>]?:\n | RequireOnlyOne<QueryFilter<MessageResponse[Key]>>\n | PrimitiveFilter<MessageResponse[Key]>;\n }\n>;\n\nexport type MessageOptions = {\n include_thread_participants?: boolean;\n};\n\nexport type PrimitiveFilter<ObjectType> = ObjectType | null;\n\nexport type QueryFilter<ObjectType = string> =\n NonNullable<ObjectType> extends string | number | boolean\n ? {\n $eq?: PrimitiveFilter<ObjectType>;\n $exists?: boolean;\n $gt?: PrimitiveFilter<ObjectType>;\n $gte?: PrimitiveFilter<ObjectType>;\n $in?: PrimitiveFilter<ObjectType>[];\n $lt?: PrimitiveFilter<ObjectType>;\n $lte?: PrimitiveFilter<ObjectType>;\n }\n : {\n $eq?: PrimitiveFilter<ObjectType>;\n $exists?: boolean;\n $in?: PrimitiveFilter<ObjectType>[];\n };\n\nexport type QueryFilters<Operators = {}> = {\n [Key in keyof Operators]?: Operators[Key];\n} & QueryLogicalOperators<Operators>;\n\nexport type QueryLogicalOperators<Operators> = {\n $and?: ArrayOneOrMore<QueryFilters<Operators>>;\n $nor?: ArrayOneOrMore<QueryFilters<Operators>>;\n $or?: ArrayTwoOrMore<QueryFilters<Operators>>;\n};\n\nexport type UserFilters = QueryFilters<\n ContainsOperator<CustomUserData> & {\n id?:\n | RequireOnlyOne<\n { $autocomplete?: UserResponse['id'] } & QueryFilter<UserResponse['id']>\n >\n | PrimitiveFilter<UserResponse['id']>;\n name?:\n | RequireOnlyOne<\n { $autocomplete?: UserResponse['name'] } & QueryFilter<UserResponse['name']>\n >\n | PrimitiveFilter<UserResponse['name']>;\n notifications_muted?:\n | RequireOnlyOne<{\n $eq?: PrimitiveFilter<UserResponse['notifications_muted']>;\n }>\n | boolean;\n teams?:\n | RequireOnlyOne<{\n $contains?: PrimitiveFilter<string>;\n $eq?: PrimitiveFilter<UserResponse['teams']>;\n $in?: PrimitiveFilter<UserResponse['teams']>;\n }>\n | PrimitiveFilter<UserResponse['teams']>;\n username?:\n | RequireOnlyOne<\n { $autocomplete?: UserResponse['username'] } & QueryFilter<\n UserResponse['username']\n >\n >\n | PrimitiveFilter<UserResponse['username']>;\n } & {\n [Key in keyof Omit<\n UserResponse,\n 'id' | 'name' | 'teams' | 'username' | keyof CustomUserData\n >]?:\n | RequireOnlyOne<QueryFilter<UserResponse[Key]>>\n | PrimitiveFilter<UserResponse[Key]>;\n }\n>;\n\nexport type InviteStatus = 'pending' | 'accepted' | 'rejected';\n\n// https://getstream.io/chat/docs/react/channel_member/#update-channel-members\nexport type MemberFilters = QueryFilters<\n {\n banned?: { $eq?: ChannelMemberResponse['banned'] } | ChannelMemberResponse['banned'];\n channel_role?:\n | { $eq?: ChannelMemberResponse['channel_role'] }\n | ChannelMemberResponse['channel_role'];\n cid?: { $eq?: ChannelResponse['cid'] } | ChannelResponse['cid'];\n created_at?:\n | {\n $eq?: ChannelMemberResponse['created_at'];\n $gt?: ChannelMemberResponse['created_at'];\n $gte?: ChannelMemberResponse['created_at'];\n $lt?: ChannelMemberResponse['created_at'];\n $lte?: ChannelMemberResponse['created_at'];\n }\n | ChannelMemberResponse['created_at'];\n id?:\n | RequireOnlyOne<{\n $eq?: UserResponse['id'];\n $in?: UserResponse['id'][];\n }>\n | UserResponse['id'];\n invite?: { $eq?: ChannelMemberResponse['status'] } | ChannelMemberResponse['status'];\n is_moderator?:\n | RequireOnlyOne<{ $eq?: ChannelMemberResponse['is_moderator'] }>\n | ChannelMemberResponse['is_moderator'];\n joined?: { $eq?: boolean } | boolean;\n last_active?:\n | {\n $eq?: UserResponse['last_active'];\n $gt?: UserResponse['last_active'];\n $gte?: UserResponse['last_active'];\n $lt?: UserResponse['last_active'];\n $lte?: UserResponse['last_active'];\n }\n | UserResponse['last_active'];\n name?:\n | RequireOnlyOne<{\n $autocomplete?: NonNullable<ChannelMemberResponse['user']>['name'];\n $eq?: NonNullable<ChannelMemberResponse['user']>['name'];\n $in?: NonNullable<ChannelMemberResponse['user']>['name'][];\n $q?: NonNullable<ChannelMemberResponse['user']>['name'];\n }>\n | PrimitiveFilter<NonNullable<ChannelMemberResponse['user']>['name']>;\n notifications_muted?:\n | RequireOnlyOne<{ $eq?: ChannelMemberResponse['notifications_muted'] }>\n | ChannelMemberResponse['notifications_muted'];\n updated_at?:\n | {\n $eq?: ChannelMemberResponse['updated_at'];\n $gt?: ChannelMemberResponse['updated_at'];\n $gte?: ChannelMemberResponse['updated_at'];\n $lt?: ChannelMemberResponse['updated_at'];\n $lte?: ChannelMemberResponse['updated_at'];\n }\n | ChannelMemberResponse['updated_at'];\n 'user.email'?:\n | RequireOnlyOne<{\n $autocomplete?: string;\n $eq?: string;\n $in?: string;\n }>\n | string;\n user_id?:\n | RequireOnlyOne<{\n $eq?: ChannelMemberResponse['user_id'];\n $in?: ChannelMemberResponse['user_id'][];\n }>\n | PrimitiveFilter<ChannelMemberResponse['user_id']>;\n } & {\n [Key in keyof ContainsOperator<CustomMemberData>]?:\n | RequireOnlyOne<QueryFilter<ContainsOperator<CustomMemberData>[Key]>>\n | PrimitiveFilter<ContainsOperator<CustomMemberData>[Key]>;\n }\n>;\n\n/**\n * Sort Types\n */\n\nexport type BannedUsersSort = BannedUsersSortBase | Array<BannedUsersSortBase>;\n\nexport type BannedUsersSortBase = { created_at?: AscDesc };\n\nexport type ReactionSort = ReactionSortBase | Array<ReactionSortBase>;\n\nexport type ReactionSortBase = Sort<CustomReactionData> & {\n created_at?: AscDesc;\n};\n\nexport type ChannelSort = ChannelSortBase | Array<ChannelSortBase>;\n\nexport type ChannelSortBase = Sort<CustomChannelData> & {\n created_at?: AscDesc;\n has_unread?: AscDesc;\n last_message_at?: AscDesc;\n last_updated?: AscDesc;\n member_count?: AscDesc;\n pinned_at?: AscDesc;\n unread_count?: AscDesc;\n updated_at?: AscDesc;\n};\n\nexport type PinnedMessagesSort = PinnedMessagesSortBase | Array<PinnedMessagesSortBase>;\nexport type PinnedMessagesSortBase = { pinned_at?: AscDesc };\n\nexport type Sort<T> = {\n [P in keyof T]?: AscDesc;\n};\n\nexport type UserSort = Sort<UserResponse> | Array<Sort<UserResponse>>;\n\nexport type MemberSort =\n | Sort<\n Pick<UserResponse, 'created_at' | 'last_active' | 'name' | 'updated_at'> & {\n user_id?: string;\n }\n >\n | Array<\n Sort<\n Pick<UserResponse, 'created_at' | 'last_active' | 'name' | 'updated_at'> & {\n user_id?: string;\n }\n >\n >;\n\nexport type SearchMessageSortBase = Sort<CustomMessageData> & {\n attachments?: AscDesc;\n 'attachments.type'?: AscDesc;\n created_at?: AscDesc;\n id?: AscDesc;\n 'mentioned_users.id'?: AscDesc;\n parent_id?: AscDesc;\n pinned?: AscDesc;\n relevance?: AscDesc;\n reply_count?: AscDesc;\n text?: AscDesc;\n type?: AscDesc;\n updated_at?: AscDesc;\n 'user.id'?: AscDesc;\n};\n\nexport type SearchMessageSort = SearchMessageSortBase | Array<SearchMessageSortBase>;\n\nexport type QuerySort = BannedUsersSort | ChannelSort | SearchMessageSort | UserSort;\n\nexport type DraftSortBase = {\n created_at?: AscDesc;\n};\n\nexport type DraftSort = DraftSortBase | Array<DraftSortBase>;\n\nexport type PollSort = PollSortBase | Array<PollSortBase>;\n\nexport type PollSortBase = {\n created_at?: AscDesc;\n id?: AscDesc;\n is_closed?: AscDesc;\n name?: AscDesc;\n updated_at?: AscDesc;\n};\n\nexport type VoteSort = VoteSortBase | Array<VoteSortBase>;\n\nexport type VoteSortBase = {\n created_at?: AscDesc;\n id?: AscDesc;\n is_closed?: AscDesc;\n name?: AscDesc;\n updated_at?: AscDesc;\n};\n\n/**\n * Base Types\n */\n\nexport type Action = {\n name?: string;\n style?: string;\n text?: string;\n type?: string;\n value?: string;\n};\n\nexport type AnonUserType = {};\n\nexport type APNConfig = {\n auth_key?: string;\n auth_type?: string;\n bundle_id?: string;\n development?: boolean;\n enabled?: boolean;\n host?: string;\n key_id?: string;\n notification_template?: string;\n p12_cert?: string;\n team_id?: string;\n};\n\nexport type AsyncModerationOptions = {\n callback?: {\n mode?: 'CALLBACK_MODE_NONE' | 'CALLBACK_MODE_REST' | 'CALLBACK_MODE_TWIRP';\n server_url?: string;\n };\n timeout_ms?: number;\n};\n\nexport type AppSettings = {\n allowed_flag_reasons?: string[];\n apn_config?: {\n auth_key?: string;\n auth_type?: string;\n bundle_id?: string;\n development?: boolean;\n host?: string;\n key_id?: string;\n notification_template?: string;\n p12_cert?: string;\n team_id?: string;\n };\n async_moderation_config?: AsyncModerationOptions;\n async_url_enrich_enabled?: boolean;\n auto_translation_enabled?: boolean;\n before_message_send_hook_url?: string;\n cdn_expiration_seconds?: number;\n custom_action_handler_url?: string;\n disable_auth_checks?: boolean;\n disable_permissions_checks?: boolean;\n enforce_unique_usernames?: 'no' | 'app' | 'team';\n event_hooks?: Array<EventHook> | null;\n explicit_event_hooks_deletion?: boolean;\n // all possible file mime types are https://www.iana.org/assignments/media-types/media-types.xhtml\n file_upload_config?: FileUploadConfig;\n firebase_config?: {\n apn_template?: string;\n credentials_json?: string;\n data_template?: string;\n notification_template?: string;\n server_key?: string;\n };\n grants?: Record<string, string[]>;\n huawei_config?: {\n id: string;\n secret: string;\n };\n image_moderation_enabled?: boolean;\n image_upload_config?: FileUploadConfig;\n migrate_permissions_to_v2?: boolean;\n multi_tenant_enabled?: boolean;\n permission_version?: 'v1' | 'v2';\n push_config?: {\n offline_only?: boolean;\n version?: string;\n };\n reminders_interval?: number;\n revoke_tokens_issued_before?: string | null;\n sns_key?: string;\n sns_secret?: string;\n sns_topic_arn?: string;\n sqs_key?: string;\n sqs_secret?: string;\n sqs_url?: string;\n user_response_time_enabled?: boolean;\n video_provider?: string;\n webhook_events?: Array<string> | null;\n webhook_url?: string;\n xiaomi_config?: {\n package_name: string;\n secret: string;\n };\n};\n\nexport type Attachment = CustomAttachmentData & {\n actions?: Action[];\n asset_url?: string;\n author_icon?: string;\n author_link?: string;\n author_name?: string;\n color?: string;\n duration?: number;\n fallback?: string;\n fields?: Field[];\n file_size?: number | string;\n footer?: string;\n footer_icon?: string;\n giphy?: GiphyData;\n image_url?: string;\n latitude?: number;\n longitude?: number;\n mime_type?: string;\n og_scrape_url?: string;\n original_height?: number;\n original_width?: number;\n pretext?: string;\n text?: string;\n thumb_url?: string;\n title?: string;\n title_link?: string;\n type?: string;\n waveform_data?: Array<number>;\n};\n\nexport type OGAttachment = {\n og_scrape_url: string;\n asset_url?: string; // og:video | og:audio\n author_link?: string; // og:site\n author_name?: string; // og:site_name\n image_url?: string; // og:image\n text?: string; // og:description\n thumb_url?: string; // og:image\n title?: string; // og:title\n title_link?: string; // og:url\n type?: string | 'video' | 'audio' | 'image';\n};\n\nexport type BlockList = {\n name: string;\n words: string[];\n team?: string;\n type?: string;\n validate?: boolean;\n};\n\nexport type ChannelConfig = ChannelConfigFields &\n CreatedAtUpdatedAt & {\n commands?: CommandVariants[];\n };\n\nexport type ChannelConfigAutomod = Automod;\n\nexport type ChannelConfigAutomodBehavior = AutomodBehavior;\n\nexport type ChannelConfigAutomodThresholds = null | Thresholds;\n\nexport type ChannelConfigFields = {\n reminders: boolean;\n automod?: ChannelConfigAutomod;\n automod_behavior?: ChannelConfigAutomodBehavior;\n automod_thresholds?: ChannelConfigAutomodThresholds;\n blocklist_behavior?: ChannelConfigAutomodBehavior;\n connect_events?: boolean;\n custom_events?: boolean;\n mark_messages_pending?: boolean;\n max_message_length?: number;\n message_retention?: string;\n mutes?: boolean;\n name?: string;\n polls?: boolean;\n push_notifications?: boolean;\n quotes?: boolean;\n reactions?: boolean;\n read_events?: boolean;\n replies?: boolean;\n search?: boolean;\n shared_locations?: boolean;\n count_messages?: boolean; // Feature flag for message count\n typing_events?: boolean;\n uploads?: boolean;\n url_enrichment?: boolean;\n user_message_reminders?: boolean; // Feature flag for user message reminders\n};\n\nexport type ChannelConfigWithInfo = ChannelConfigFields &\n CreatedAtUpdatedAt & {\n commands?: CommandResponse[];\n };\n\nexport type ChannelData = CustomChannelData &\n Partial<{\n blocked: boolean;\n created_by: UserResponse | null;\n created_by_id: UserResponse['id'];\n members: string[] | Array<NewMemberPayload>;\n blocklist_behavior: AutomodBehavior;\n automod: Automod;\n }>;\n\nexport type ChannelMute = {\n user: UserResponse;\n channel?: ChannelResponse;\n created_at?: string;\n expires?: string;\n updated_at?: string;\n};\n\nexport type ChannelRole = {\n custom?: boolean;\n name?: string;\n owner?: boolean;\n resource?: string;\n same_team?: boolean;\n};\n\nexport type CheckPushInput = {\n apn_template?: string;\n client_id?: string;\n connection_id?: string;\n firebase_data_template?: string;\n firebase_template?: string;\n message_id?: string;\n user?: UserResponse;\n user_id?: string;\n};\n\nexport type PushProvider = 'apn' | 'firebase' | 'huawei' | 'xiaomi';\n\nexport type PushProviderConfig = PushProviderCommon &\n PushProviderID &\n PushProviderAPN &\n PushProviderFirebase &\n PushProviderHuawei &\n PushProviderXiaomi;\n\nexport type PushProviderID = {\n name: string;\n type: PushProvider;\n};\n\nexport type PushProviderCommon = {\n created_at: string;\n updated_at: string;\n description?: string;\n disabled_at?: string;\n disabled_reason?: string;\n};\n\nexport type PushProviderAPN = {\n apn_auth_key?: string;\n apn_auth_type?: 'token' | 'certificate';\n apn_development?: boolean;\n apn_host?: string;\n apn_key_id?: string;\n apn_notification_template?: string;\n apn_p12_cert?: string;\n apn_team_id?: string;\n apn_topic?: string;\n};\n\nexport type PushProviderFirebase = {\n firebase_apn_template?: string;\n firebase_credentials?: string;\n firebase_data_template?: string;\n firebase_notification_template?: string;\n firebase_server_key?: string;\n};\n\nexport type PushProviderHuawei = {\n huawei_app_id?: string;\n huawei_app_secret?: string;\n};\n\nexport type PushProviderXiaomi = {\n xiaomi_package_name?: string;\n xiaomi_secret?: string;\n};\n\nexport type CommandVariants =\n | 'all'\n | 'ban'\n | 'fun_set'\n | 'giphy'\n | 'moderation_set'\n | 'mute'\n | 'unban'\n | 'unmute'\n | keyof CustomCommandData;\n\nexport type Configs = Record<string, ChannelConfigWithInfo | undefined>;\n\nexport type ConnectionOpen = {\n connection_id: string;\n cid?: string;\n created_at?: string;\n me?: OwnUserResponse;\n type?: string;\n};\n\nexport type CreatedAtUpdatedAt = {\n created_at: string;\n updated_at: string;\n};\n\nexport type Device = DeviceFields & {\n provider?: string;\n user?: UserResponse;\n user_id?: string;\n};\n\nexport type BaseDeviceFields = {\n id: string;\n push_provider: PushProvider;\n push_provider_name?: string;\n};\n\nexport type DeviceFields = BaseDeviceFields & {\n created_at: string;\n disabled?: boolean;\n disabled_reason?: string;\n};\n\nexport type EndpointName =\n | 'Connect'\n | 'LongPoll'\n | 'DeleteFile'\n | 'DeleteImage'\n | 'DeleteMessage'\n | 'DeleteUser'\n | 'DeleteUsers'\n | 'DeactivateUser'\n | 'ExportUser'\n | 'DeleteReaction'\n | 'UpdateChannel'\n | 'UpdateChannelPartial'\n | 'UpdateMessage'\n | 'UpdateMessagePartial'\n | 'GetMessage'\n | 'GetManyMessages'\n | 'UpdateUsers'\n | 'UpdateUsersPartial'\n | 'CreateGuest'\n | 'GetOrCreateChannel'\n | 'StopWatchingChannel'\n | 'QueryChannels'\n | 'Search'\n | 'QueryUsers'\n | 'QueryMembers'\n | 'QueryBannedUsers'\n | 'QueryFlags'\n | 'QueryMessageFlags'\n | 'GetReactions'\n | 'GetReplies'\n | 'GetPinnedMessages'\n | 'Ban'\n | 'Unban'\n | 'MuteUser'\n | 'MuteChannel'\n | 'UnmuteChannel'\n | 'UnmuteUser'\n | 'RunMessageAction'\n | 'SendEvent'\n | 'SendUserCustomEvent'\n | 'MarkRead'\n | 'MarkChannelsRead'\n | 'SendMessage'\n | 'ImportChannelMessages'\n | 'UploadFile'\n | 'UploadImage'\n | 'UpdateApp'\n | 'GetApp'\n | 'CreateDevice'\n | 'DeleteDevice'\n | 'SendReaction'\n | 'Flag'\n | 'Unflag'\n | 'Unblock'\n | 'QueryFlagReports'\n | 'FlagReportReview'\n | 'CreateChannelType'\n | 'DeleteChannel'\n | 'DeleteChannels'\n | 'DBDeleteChannelType'\n | 'GetChannelType'\n | 'ListChannelTypes'\n | 'ListDevices'\n | 'TruncateChannel'\n | 'UpdateChannelType'\n | 'CheckPush'\n | 'PrivateSubmitModeration'\n | 'ReactivateUser'\n | 'HideChannel'\n | 'ShowChannel'\n | 'CreatePermission'\n | 'UpdatePermission'\n | 'GetPermission'\n | 'DeletePermission'\n | 'ListPermissions'\n | 'CreateRole'\n | 'DeleteRole'\n | 'ListRoles'\n | 'ListCustomRoles'\n | 'Sync'\n | 'TranslateMessage'\n | 'CreateCommand'\n | 'GetCommand'\n | 'UpdateCommand'\n | 'DeleteCommand'\n | 'ListCommands'\n | 'CreateBlockList'\n | 'UpdateBlockList'\n | 'GetBlockList'\n | 'ListBlockLists'\n | 'DeleteBlockList'\n | 'ExportChannels'\n | 'GetExportChannelsStatus'\n | 'CheckSQS'\n | 'GetRateLimits'\n | 'CreateSegment'\n | 'GetSegment'\n | 'QuerySegments'\n | 'UpdateSegment'\n | 'DeleteSegment'\n | 'CreateCampaign'\n | 'GetCampaign'\n | 'ListCampaigns'\n | 'UpdateCampaign'\n | 'DeleteCampaign'\n | 'ScheduleCampaign'\n | 'StopCampaign'\n | 'ResumeCampaign'\n | 'TestCampaign'\n | 'GetOG'\n | 'GetTask'\n | 'ExportUsers'\n | 'CreateImport'\n | 'CreateImportURL'\n | 'GetImport'\n | 'ListImports'\n | 'UpsertPushProvider'\n | 'DeletePushProvider'\n | 'ListPushProviders'\n | 'CreatePoll';\n\nexport type ExportChannelRequest = (\n | {\n id: string;\n type: string;\n }\n | {\n cid: string;\n }\n) & { messages_since?: Date; messages_until?: Date };\n\nexport type ExportChannelOptions = {\n clear_deleted_message_text?: boolean;\n export_users?: boolean;\n include_soft_deleted_channels?: boolean;\n include_truncated_messages?: boolean;\n version?: string;\n};\n\nexport type ExportUsersRequest = {\n user_ids: string[];\n};\n\nexport type Field = {\n short?: boolean;\n title?: string;\n value?: string;\n};\n\nexport type FileUploadConfig = {\n allowed_file_extensions?: string[] | null;\n allowed_mime_types?: string[] | null;\n blocked_file_extensions?: string[] | null;\n blocked_mime_types?: string[] | null;\n size_limit?: number | null;\n};\n\nexport type FirebaseConfig = {\n apn_template?: string;\n credentials_json?: string;\n data_template?: string;\n enabled?: boolean;\n notification_template?: string;\n server_key?: string;\n};\n\ntype GiphyVersionInfo = {\n height: string;\n url: string;\n width: string;\n frames?: string;\n size?: string;\n};\n\ntype GiphyVersions =\n | 'original'\n | 'fixed_height'\n | 'fixed_height_still'\n | 'fixed_height_downsampled'\n | 'fixed_width'\n | 'fixed_width_still'\n | 'fixed_width_downsampled';\n\ntype GiphyData = {\n [key in GiphyVersions]: GiphyVersionInfo;\n};\n\nexport type HuaweiConfig = {\n enabled?: boolean;\n id?: string;\n secret?: string;\n};\n\nexport type XiaomiConfig = {\n enabled?: boolean;\n package_name?: string;\n secret?: string;\n};\n\nexport type LiteralStringForUnion = string & {};\n\nexport type LogLevel = 'info' | 'error' | 'warn';\n\nexport type Logger = (\n logLevel: LogLevel,\n message: string,\n extraData?: Record<string, unknown>,\n) => void;\n\nexport type Message = Partial<\n MessageBase & {\n mentioned_users: string[];\n shared_location?: StaticLocationPayload | LiveLocationPayload;\n }\n>;\n\nexport type MessageBase = CustomMessageData & {\n id: string;\n attachments?: Attachment[];\n html?: string;\n mml?: string;\n parent_id?: string;\n pin_expires?: string | null;\n pinned?: boolean;\n pinned_at?: string | null;\n poll_id?: string;\n quoted_message_id?: string;\n restricted_visibility?: string[];\n show_in_channel?: boolean;\n silent?: boolean;\n text?: string;\n type?: MessageLabel;\n user?: UserResponse | null;\n user_id?: string;\n};\n\nexport type MessageLabel =\n | 'deleted'\n | 'ephemeral'\n | 'error'\n | 'regular'\n | 'reply'\n | 'system';\n\nexport type SendMessageOptions = {\n force_moderation?: boolean;\n // @deprecated use `pending` instead\n is_pending_message?: boolean;\n keep_channel_hidden?: boolean;\n pending?: boolean;\n pending_message_metadata?: Record<string, string>;\n skip_enrich_url?: boolean;\n skip_push?: boolean;\n};\n\nexport type UpdateMessageOptions = {\n skip_enrich_url?: boolean;\n skip_push?: boolean;\n};\n\nexport type SendReactionOptions = {\n enforce_unique?: boolean;\n skip_push?: boolean;\n};\n\nexport type GetMessageOptions = {\n show_deleted_message?: boolean;\n};\n\nexport type Mute = {\n created_at: string;\n target: UserResponse;\n updated_at: string;\n user: UserResponse;\n};\n\nexport type PartialUpdateChannel = {\n set?: Partial<ChannelResponse>;\n unset?: Array<keyof ChannelResponse>;\n};\n\nexport type PartialUpdateMember = {\n set?: ChannelMemberUpdates;\n unset?: Array<keyof ChannelMemberUpdates>;\n};\n\nexport type PartialUserUpdate = {\n id: string;\n set?: Partial<UserResponse>;\n unset?: Array<keyof UserResponse>;\n};\n\nexport type MessageUpdatableFields = Omit<\n MessageResponse,\n 'cid' | 'created_at' | 'updated_at' | 'deleted_at' | 'user' | 'user_id'\n>;\n\nexport type PartialMessageUpdate = {\n set?: Partial<MessageUpdatableFields>;\n unset?: Array<keyof MessageUpdatableFields>;\n};\n\nexport type PendingMessageResponse = {\n message: MessageResponse;\n pending_message_metadata?: Record<string, string>;\n};\n\nexport type PermissionAPIObject = {\n action?: string;\n condition?: object;\n custom?: boolean;\n description?: string;\n id?: string;\n level?: string;\n name?: string;\n owner?: boolean;\n same_team?: boolean;\n tags?: string[];\n};\n\nexport type PermissionObject = {\n action?: 'Deny' | 'Allow';\n name?: string;\n owner?: boolean;\n priority?: number;\n resources?: string[];\n roles?: string[];\n};\n\nexport type Policy = {\n action?: 0 | 1;\n created_at?: string;\n name?: string;\n owner?: boolean;\n priority?: number;\n resources?: string[];\n roles?: string[] | null;\n updated_at?: string;\n};\n\nexport type RateLimitsInfo = {\n limit: number;\n remaining: number;\n reset: number;\n};\n\nexport type RateLimitsMap = Record<EndpointName, RateLimitsInfo>;\n\nexport type Reaction = CustomReactionData & {\n type: string;\n message_id?: string;\n score?: number;\n user?: UserResponse | null;\n user_id?: string;\n emoji_code?: string;\n};\n\nexport type Resource =\n | 'AddLinks'\n | 'BanUser'\n | 'CreateChannel'\n | 'CreateMessage'\n | 'CreateReaction'\n | 'DeleteAttachment'\n | 'DeleteChannel'\n | 'DeleteMessage'\n | 'DeleteReaction'\n | 'EditUser'\n | 'MuteUser'\n | 'ReadChannel'\n | 'RunMessageAction'\n | 'UpdateChannel'\n | 'UpdateChannelMembers'\n | 'UpdateMessage'\n | 'UpdateUser'\n | 'UploadAttachment';\n\nexport type SearchPayload = Omit<SearchOptions, 'sort'> & {\n client_id?: string;\n connection_id?: string;\n filter_conditions?: ChannelFilters;\n message_filter_conditions?: MessageFilters;\n message_options?: MessageOptions;\n query?: string;\n sort?: Array<{\n direction: AscDesc;\n field: keyof SearchMessageSortBase;\n }>;\n};\n\nexport type TestPushDataInput = {\n apnTemplate?: string;\n firebaseDataTemplate?: string;\n firebaseTemplate?: string;\n messageID?: string;\n pushProviderName?: string;\n pushProviderType?: PushProvider;\n skipDevices?: boolean;\n};\n\nexport type TestSQSDataInput = {\n sqs_key?: string;\n sqs_secret?: string;\n sqs_url?: string;\n};\n\nexport type TestSNSDataInput = {\n sns_key?: string;\n sns_secret?: string;\n sns_topic_arn?: string;\n};\n\nexport type TokenOrProvider = null | string | TokenProvider | undefined;\n\nexport type TokenProvider = () => Promise<string>;\n\nexport type TranslationLanguages =\n | 'af'\n | 'am'\n | 'ar'\n | 'az'\n | 'bg'\n | 'bn'\n | 'bs'\n | 'cs'\n | 'da'\n | 'de'\n | 'el'\n | 'en'\n | 'es'\n | 'es-MX'\n | 'et'\n | 'fa'\n | 'fa-AF'\n | 'fi'\n | 'fr'\n | 'fr-CA'\n | 'ha'\n | 'he'\n | 'hi'\n | 'hr'\n | 'hu'\n | 'id'\n | 'it'\n | 'ja'\n | 'ka'\n | 'ko'\n | 'lt'\n | 'lv'\n | 'ms'\n | 'nl'\n | 'no'\n | 'pl'\n | 'ps'\n | 'pt'\n | 'ro'\n | 'ru'\n | 'sk'\n | 'sl'\n | 'so'\n | 'sq'\n | 'sr'\n | 'sv'\n | 'sw'\n | 'ta'\n | 'th'\n | 'tl'\n | 'tr'\n | 'uk'\n | 'ur'\n | 'vi'\n | 'zh'\n | 'zh-TW'\n | (string & {});\n\nexport type TypingStartEvent = Event;\n\nexport type ReservedUpdatedMessageFields = keyof typeof RESERVED_UPDATED_MESSAGE_FIELDS;\n\nexport type UpdatedMessage = Omit<MessageResponse, ReservedUpdatedMessageFields> & {\n mentioned_users?: string[];\n type?: MessageLabel;\n};\n\n/**\n * @description type alias for UserResponse\n */\nexport type User = UserResponse;\n\nexport type TaskResponse = {\n task_id: string;\n};\n\nexport type DeleteChannelsResponse = {\n result: Record<string, string>;\n} & Partial<TaskResponse>;\n\nexport type DeleteType = 'soft' | 'hard' | 'pruning';\n\n/*\n DeleteUserOptions specifies a collection of one or more `user_ids` to be deleted.\n\n `user`:\n - soft: marks user as deleted and retains all user data\n - pruning: marks user as deleted and nullifies user information\n - hard: deletes user completely - this requires hard option for messages and conversation as well\n `conversations`:\n - soft: marks all conversation channels as deleted (same effect as Delete Channels with 'hard' option disabled)\n - hard: deletes channel and all its data completely including messages (same effect as Delete Channels with 'hard' option enabled)\n `messages`:\n - soft: marks all user messages as deleted without removing any related message data\n - pruning: marks all user messages as deleted, nullifies message information and removes some message data such as reactions and flags\n - hard: deletes messages completely with all related information\n `new_channel_owner_id`: any channels owned by the hard-deleted user will be transferred to this user ID\n */\nexport type DeleteUserOptions = {\n conversations?: Exclude<DeleteType, 'pruning'>;\n messages?: DeleteType;\n new_channel_owner_id?: string;\n user?: DeleteType;\n};\n\nexport type SegmentType = 'channel' | 'user';\n\nexport type SegmentData = {\n all_sender_channels?: boolean;\n all_users?: boolean;\n description?: string;\n filter?: {};\n name?: string;\n};\n\nexport type SegmentResponse = {\n created_at: string;\n deleted_at: string;\n id: string;\n locked: boolean;\n size: number;\n task_id: string;\n type: SegmentType;\n updated_at: string;\n} & SegmentData;\n\nexport type UpdateSegmentData = {\n name: string;\n} & SegmentData;\n\nexport type SegmentTargetsResponse = {\n created_at: string;\n segment_id: string;\n target_id: string;\n};\n\nexport type SortParam = {\n field: string;\n direction?: AscDesc;\n};\n\nexport type Pager = {\n limit?: number;\n next?: string;\n prev?: string;\n};\n\nexport type QuerySegmentsOptions = Pager;\n\nexport type QuerySegmentTargetsFilter = {\n target_id?: {\n $eq?: string;\n $gte?: string;\n $in?: string[];\n $lte?: string;\n };\n};\nexport type QuerySegmentTargetsOptions = Pick<Pager, 'next' | 'limit'>;\n\nexport type GetCampaignOptions = {\n users?: { limit?: number; next?: string; prev?: string };\n};\n\nexport type CampaignSort = {\n field: string;\n direction?: number;\n}[];\n\nexport type CampaignQueryOptions = {\n limit?: number;\n next?: string;\n prev?: string;\n sort?: CampaignSort;\n user_limit?: number;\n};\n\nexport type SegmentQueryOptions = CampaignQueryOptions;\n\n// TODO: add better typing\nexport type CampaignFilters = {};\n\nexport type CampaignData = {\n channel_template?: {\n type: string;\n custom?: {};\n id?: string;\n members?: string[];\n team?: string;\n };\n create_channels?: boolean;\n deleted_at?: string;\n description?: string;\n id?: string | null;\n message_template?: {\n text: string;\n attachments?: Attachment[];\n custom?: {};\n poll_id?: string;\n };\n name?: string;\n segment_ids?: string[];\n sender_id?: string;\n sender_mode?: 'exclude' | 'include' | null;\n sender_visibility?: 'hidden' | 'archived' | null;\n show_channels?: boolean;\n skip_push?: boolean;\n skip_webhook?: boolean;\n user_ids?: string[];\n};\n\nexport type CampaignStats = {\n progress?: number;\n stats_channels_created?: number;\n stats_completed_at?: string;\n stats_messages_sent?: number;\n stats_started_at?: string;\n stats_users_read?: number;\n stats_users_sent?: number;\n};\nexport type CampaignResponse = {\n created_at: string;\n id: string;\n segments: SegmentResponse[];\n sender: UserResponse;\n stats: CampaignStats;\n status: 'draft' | 'scheduled' | 'in_progress' | 'completed' | 'stopped';\n updated_at: string;\n users: UserResponse[];\n scheduled_for?: string;\n} & CampaignData;\n\nexport type DeleteCampaignOptions = {};\n\nexport type TaskStatus = {\n created_at: string;\n status: string;\n task_id: string;\n updated_at: string;\n error?: {\n description: string;\n type: string;\n };\n result?: UR;\n};\n\nexport type TruncateOptions = {\n hard_delete?: boolean;\n message?: Message;\n skip_push?: boolean;\n truncated_at?: Date;\n user?: UserResponse;\n user_id?: string;\n};\n\nexport type CreateImportURLResponse = {\n path: string;\n upload_url: string;\n};\n\nexport type CreateImportResponse = {\n import_task: ImportTask;\n};\n\nexport type GetImportResponse = {\n import_task: ImportTask;\n};\n\nexport type CreateImportOptions = {\n mode: 'insert' | 'upsert';\n};\n\nexport type ListImportsPaginationOptions = {\n limit?: number;\n offset?: number;\n};\n\nexport type ListImportsResponse = {\n import_tasks: ImportTask[];\n};\n\nexport type ImportTaskHistory = {\n created_at: string;\n next_state: string;\n prev_state: string;\n};\n\nexport type ImportTask = {\n created_at: string;\n history: ImportTaskHistory[];\n id: string;\n path: string;\n state: string;\n updated_at: string;\n result?: UR;\n size?: number;\n};\n\nexport type MessageSetType = 'latest' | 'current' | 'new';\nexport type MessageSet = {\n isCurrent: boolean;\n isLatest: boolean;\n messages: LocalMessage[];\n pagination: { hasNext: boolean; hasPrev: boolean };\n};\n\nexport type PushProviderUpsertResponse = {\n push_provider: PushProvider;\n};\n\nexport type PushProviderListResponse = {\n push_providers: PushProvider[];\n};\n\ntype ErrorResponseDetails = {\n code: number;\n messages: string[];\n};\n\nexport type APIErrorResponse = {\n duration: string;\n message: string;\n more_info: string;\n StatusCode: number;\n code?: number;\n details?: ErrorResponseDetails;\n};\n\nexport class ErrorFromResponse<T> extends Error {\n public code: number | null;\n public status: number;\n public response: AxiosResponse<T>;\n public name = 'ErrorFromResponse';\n\n constructor(\n message: string,\n {\n code,\n status,\n response,\n }: {\n code: ErrorFromResponse<T>['code'];\n response: ErrorFromResponse<T>['response'];\n status: ErrorFromResponse<T>['status'];\n },\n ) {\n super(message);\n this.code = code;\n this.response = response;\n this.status = status;\n }\n\n // Vitest helper (serialized errors are too large to read)\n // https://github.com/vitest-dev/vitest/blob/v3.1.3/packages/utils/src/error.ts#L60-L62\n toJSON() {\n const extra = [\n ['status', this.status],\n ['code', this.code],\n ] as const;\n\n const joinable = [];\n\n for (const [key, value] of extra) {\n if (typeof value !== 'undefined' && value !== null) {\n joinable.push(`${key}: ${value}`);\n }\n }\n\n return {\n message: `(${joinable.join(', ')}) - ${this.message}`,\n stack: this.stack,\n name: this.name,\n code: this.code,\n status: this.status,\n } as const;\n }\n}\n\nexport type QueryPollsResponse = {\n polls: PollResponse[];\n next?: string;\n};\n\nexport type CreatePollAPIResponse = {\n poll: PollResponse;\n};\n\nexport type GetPollAPIResponse = {\n poll: PollResponse;\n};\n\nexport type UpdatePollAPIResponse = {\n poll: PollResponse;\n};\n\nexport type PollResponse = CustomPollData &\n PollEnrichData & {\n created_at: string;\n created_by: UserResponse | null;\n created_by_id: string;\n enforce_unique_vote: boolean;\n id: string;\n max_votes_allowed: number;\n name: string;\n options: PollOption[];\n updated_at: string;\n allow_answers?: boolean;\n allow_user_suggested_options?: boolean;\n description?: string;\n is_closed?: boolean;\n voting_visibility?: VotingVisibility;\n };\n\nexport type PollOption = {\n created_at: string;\n id: string;\n poll_id: string;\n text: string;\n updated_at: string;\n vote_count: number;\n votes?: PollVote[];\n};\n\nexport enum VotingVisibility {\n anonymous = 'anonymous',\n public = 'public',\n}\n\nexport type PollEnrichData = {\n answers_count: number;\n latest_answers: PollAnswer[]; // not updated with WS events, ordered DESC by created_at, seems like updated_at cannot be different from created_at\n latest_votes_by_option: Record<string, PollVote[]>; // not updated with WS events; always null in anonymous polls\n vote_count: number;\n vote_counts_by_option: Record<string, number>;\n own_votes?: (PollVote | PollAnswer)[]; // not updated with WS events\n};\n\nexport type PollData = CustomPollData & {\n id: string;\n name: string;\n allow_answers?: boolean;\n allow_user_suggested_options?: boolean;\n description?: string;\n enforce_unique_vote?: boolean;\n is_closed?: boolean;\n max_votes_allowed?: number;\n options?: PollOptionData[];\n user_id?: string;\n voting_visibility?: VotingVisibility;\n};\n\nexport type CreatePollData = Partial<PollData> & Pick<PollData, 'name'>;\n\nexport type PartialPollUpdate = {\n set?: Partial<PollData>;\n unset?: Array<keyof PollData>;\n};\n\nexport type PollOptionData = CustomPollOptionData & {\n text: string;\n id?: string;\n position?: number;\n};\n\nexport type PartialPollOptionUpdate = {\n set?: Partial<PollOptionResponse>;\n unset?: Array<keyof PollOptionResponse>;\n};\n\nexport type PollVoteData = {\n answer_text?: string;\n is_answer?: boolean;\n option_id?: string;\n};\n\nexport type PollPaginationOptions = {\n limit?: number;\n next?: string;\n};\n\nexport type CreatePollOptionAPIResponse = {\n poll_option: PollOptionResponse;\n};\n\nexport type GetPollOptionAPIResponse = CreatePollOptionAPIResponse;\nexport type UpdatePollOptionAPIResponse = CreatePollOptionAPIResponse;\n\nexport type PollOptionResponse = CustomPollData & {\n created_at: string;\n id: string;\n poll_id: string;\n position: number;\n text: string;\n updated_at: string;\n vote_count: number;\n votes?: PollVote[];\n};\n\nexport type PollVote = {\n created_at: string;\n id: string;\n poll_id: string;\n updated_at: string;\n option_id?: string;\n user?: UserResponse;\n user_id?: string;\n};\n\nexport type PollAnswer = Exclude<PollVote, 'option_id'> & {\n answer_text: string;\n is_answer: boolean; // this is absolutely redundant prop as answer_text indicates that a vote is an answer\n};\n\nexport type PollVotesAPIResponse = {\n votes: (PollVote | PollAnswer)[];\n next?: string;\n};\n\nexport type PollAnswersAPIResponse = {\n votes: PollAnswer[]; // todo: should be changes to answers?\n next?: string;\n};\n\nexport type CastVoteAPIResponse = {\n vote: PollVote | PollAnswer;\n};\n\nexport type QueryMessageHistoryFilters = QueryFilters<\n {\n message_id?:\n | RequireOnlyOne<\n Pick<QueryFilter<MessageHistoryEntry['message_id']>, '$eq' | '$in'>\n >\n | PrimitiveFilter<MessageHistoryEntry['message_id']>;\n } & {\n user_id?:\n | RequireOnlyOne<\n Pick<QueryFilter<MessageHistoryEntry['message_updated_by_id']>, '$eq' | '$in'>\n >\n | PrimitiveFilter<MessageHistoryEntry['message_updated_by_id']>;\n } & {\n created_at?:\n | RequireOnlyOne<\n Pick<\n QueryFilter<MessageHistoryEntry['message_updated_at']>,\n '$eq' | '$gt' | '$lt' | '$gte' | '$lte'\n >\n >\n | PrimitiveFilter<MessageHistoryEntry['message_updated_at']>;\n }\n>;\n\nexport type QueryMessageHistorySort =\n | QueryMessageHistorySortBase\n | Array<QueryMessageHistorySortBase>;\n\nexport type QueryMessageHistorySortBase = {\n message_updated_at?: AscDesc;\n message_updated_by_id?: AscDesc;\n};\n\nexport type QueryMessageHistoryOptions = Pager;\n\nexport type MessageHistoryEntry = {\n message_id: string;\n message_updated_at: string;\n attachments?: Attachment[];\n message_updated_by_id?: string;\n text?: string;\n};\n\nexport type QueryMessageHistoryResponse = {\n message_history: MessageHistoryEntry[];\n next?: string;\n prev?: string;\n};\n\n// Moderation v2\nexport type ModerationPayload = {\n created_at: string;\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n custom?: Record<string, any>;\n images?: string[];\n texts?: string[];\n videos?: string[];\n};\n\nexport type ModV2ReviewStatus = 'complete' | 'flagged' | 'partial';\n\nexport type ModerationFlag = {\n created_at: string;\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n custom: Record<string, any>;\n entity_creator_id: string;\n entity_id: string;\n entity_type: string;\n id: string;\n reason: string;\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n result: Record<string, any>[];\n review_queue_item_id: string;\n updated_at: string;\n user: UserResponse;\n moderation_payload?: ModerationPayload;\n moderation_payload_hash?: string;\n};\n\nexport type ReviewQueueItem = {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n actions_taken: any[];\n appealed_by: string;\n assigned_to: string;\n completed_at: string;\n config_key: string;\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n context: any[];\n created_at: string;\n created_by: string;\n entity_id: string;\n entity_type: string;\n flags: ModerationFlag[];\n has_image: boolean;\n has_text: boolean;\n has_video: boolean;\n id: string;\n moderation_payload: ModerationPayload;\n moderation_payload_hash: string;\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n options: any;\n recommended_action: string;\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n results: any;\n reviewed_at: string;\n status: string;\n updated_at: string;\n};\n\nexport type CustomCheckFlag = {\n type: string;\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n custom?: Record<string, any>[];\n labels?: string[];\n reason?: string;\n};\n\nexport type DeleteMessagesOptions = 'soft' | 'hard';\n\nexport type SubmitActionOptions = {\n ban?: {\n channel_ban_only?: boolean;\n reason?: string;\n timeout?: number;\n delete_messages?: DeleteMessagesOptions;\n };\n delete_message?: {\n hard_delete?: boolean;\n };\n delete_user?: {\n delete_conversation_channels?: boolean;\n hard_delete?: boolean;\n mark_messages_deleted?: boolean;\n };\n restore?: {};\n unban?: {\n channel_cid?: string;\n };\n user_id?: string;\n};\n\nexport type GetUserModerationReportResponse = {\n user: UserResponse;\n user_blocks?: Array<{\n blocked_at: string;\n blocked_by_user_id: string;\n blocked_user_id: string;\n }>;\n user_mutes?: Mute[];\n};\n\nexport type QueryModerationConfigsFilters = QueryFilters<\n {\n key?: string;\n } & {\n created_at?: PrimitiveFilter<string>;\n } & {\n updated_at?: PrimitiveFilter<string>;\n } & {\n team?: string;\n }\n>;\n\nexport type ReviewQueueFilters = QueryFilters<\n {\n assigned_to?:\n | RequireOnlyOne<Pick<QueryFilter<ReviewQueueItem['assigned_to']>, '$eq' | '$in'>>\n | PrimitiveFilter<ReviewQueueItem['assigned_to']>;\n } & {\n completed_at?:\n | RequireOnlyOne<\n Pick<\n QueryFilter<ReviewQueueItem['completed_at']>,\n '$eq' | '$gt' | '$lt' | '$gte' | '$lte'\n >\n >\n | PrimitiveFilter<ReviewQueueItem['completed_at']>;\n } & {\n config_key?:\n | RequireOnlyOne<Pick<QueryFilter<ReviewQueueItem['config_key']>, '$eq' | '$in'>>\n | PrimitiveFilter<ReviewQueueItem['config_key']>;\n } & {\n entity_type?:\n | RequireOnlyOne<Pick<QueryFilter<ReviewQueueItem['entity_type']>, '$eq' | '$in'>>\n | PrimitiveFilter<ReviewQueueItem['entity_type']>;\n } & {\n created_at?:\n | RequireOnlyOne<\n Pick<\n QueryFilter<ReviewQueueItem['created_at']>,\n '$eq' | '$gt' | '$lt' | '$gte' | '$lte'\n >\n >\n | PrimitiveFilter<ReviewQueueItem['created_at']>;\n } & {\n id?:\n | RequireOnlyOne<Pick<QueryFilter<ReviewQueueItem['id']>, '$eq' | '$in'>>\n | PrimitiveFilter<ReviewQueueItem['id']>;\n } & {\n entity_id?:\n | RequireOnlyOne<Pick<QueryFilter<ReviewQueueItem['entity_id']>, '$eq' | '$in'>>\n | PrimitiveFilter<ReviewQueueItem['entity_id']>;\n } & {\n reviewed?: boolean;\n } & {\n reviewed_at?:\n | RequireOnlyOne<\n Pick<\n QueryFilter<ReviewQueueItem['reviewed_at']>,\n '$eq' | '$gt' | '$lt' | '$gte' | '$lte'\n >\n >\n | PrimitiveFilter<ReviewQueueItem['reviewed_at']>;\n } & {\n status?:\n | RequireOnlyOne<Pick<QueryFilter<ReviewQueueItem['status']>, '$eq' | '$in'>>\n | PrimitiveFilter<ReviewQueueItem['status']>;\n } & {\n updated_at?:\n | RequireOnlyOne<\n Pick<\n QueryFilter<ReviewQueueItem['updated_at']>,\n '$eq' | '$gt' | '$lt' | '$gte' | '$lte'\n >\n >\n | PrimitiveFilter<ReviewQueueItem['updated_at']>;\n } & {\n has_image?: boolean;\n } & {\n has_text?: boolean;\n } & {\n has_video?: boolean;\n } & {\n has_media?: boolean;\n } & {\n language?: RequireOnlyOne<{\n $contains?: string;\n $eq?: string;\n $in?: string[];\n }>;\n } & {\n teams?:\n | RequireOnlyOne<{\n $contains?: PrimitiveFilter<string>;\n $eq?: PrimitiveFilter<string>;\n $in?: PrimitiveFilter<string>;\n }>\n | PrimitiveFilter<string>;\n } & {\n user_report_reason?: RequireOnlyOne<{\n $eq?: string;\n }>;\n } & {\n recommended_action?: RequireOnlyOne<{\n $eq?: string;\n }>;\n } & {\n flagged_user_id?: RequireOnlyOne<{\n $eq?: string;\n }>;\n } & {\n category?: RequireOnlyOne<{\n $eq?: string;\n }>;\n } & {\n label?: RequireOnlyOne<{\n $eq?: string;\n }>;\n } & {\n reporter_type?: RequireOnlyOne<{\n $eq?: 'automod' | 'user' | 'moderator' | 'admin' | 'velocity_filter';\n }>;\n } & {\n reporter_id?: RequireOnlyOne<{\n $eq?: string;\n $in?: string[];\n }>;\n } & {\n date_range?: RequireOnlyOne<{\n $eq?: string; // Format: \"date1_date2\"\n }>;\n }\n>;\n\nexport type ReviewQueueSort =\n | Sort<Pick<ReviewQueueItem, 'id' | 'created_at' | 'updated_at'>>\n | Array<Sort<Pick<ReviewQueueItem, 'id' | 'created_at' | 'updated_at'>>>;\n\nexport type QueryModerationConfigsSort = Array<Sort<'key' | 'created_at' | 'updated_at'>>;\n\nexport type ReviewQueuePaginationOptions = Pager;\n\nexport type ReviewQueueResponse = {\n items: ReviewQueueItem[];\n next?: string;\n prev?: string;\n};\n\nexport type ModerationConfig = {\n key: string;\n ai_image_config?: AIImageConfig;\n ai_text_config?: AITextConfig;\n ai_video_config?: AIVideoConfig;\n automod_platform_circumvention_config?: AutomodPlatformCircumventionConfig;\n automod_semantic_filters_config?: AutomodSemanticFiltersConfig;\n automod_toxicity_config?: AutomodToxicityConfig;\n block_list_config?: BlockListConfig;\n team?: string;\n};\n\nexport type ModerationConfigResponse = ModerationConfig & {\n created_at: string;\n updated_at: string;\n};\n\nexport type GetConfigResponse = {\n config: ModerationConfigResponse;\n};\n\nexport type QueryConfigsResponse = {\n configs: ModerationConfigResponse[];\n next?: string;\n prev?: string;\n};\n\nexport type UpsertConfigResponse = {\n config: ModerationConfigResponse;\n};\n\n// Moderation Rule Builder Types\nexport type ModerationRule = {\n id: string;\n name: string;\n description: string;\n config_keys: string[];\n team: string;\n rule: RuleBuilderRule;\n enabled: boolean;\n created_at: string;\n updated_at: string;\n};\n\nexport type ModerationRuleRequest = {\n name: string;\n description: string;\n config_keys: string[];\n team: string;\n rule: RuleBuilderRule;\n enabled: boolean;\n};\n\nexport type RuleBuilderRule = {\n id: string;\n rule_type: 'user' | 'content';\n conditions?: RuleBuilderCondition[];\n logic?: 'AND' | 'OR';\n groups?: RuleBuilderConditionGroup[];\n action: RuleBuilderAction;\n cooldown_period?: string;\n};\n\nexport type RuleBuilderCondition = {\n type: string;\n confidence?: number;\n text_rule_params?: TextRuleParameters;\n image_rule_params?: ImageRuleParameters;\n video_rule_params?: VideoRuleParameters;\n user_rule_params?: UserRuleParameters;\n content_count_rule_params?: ContentCountRuleParameters;\n text_content_params?: TextContentParameters;\n image_content_params?: ImageContentParameters;\n video_content_params?: VideoContentParameters;\n user_created_within_params?: UserCreatedWithinParameters;\n user_custom_property_params?: UserCustomPropertyParameters;\n};\n\nexport type RuleBuilderConditionGroup = {\n logic: 'AND' | 'OR';\n conditions: RuleBuilderCondition[];\n};\n\nexport type RuleBuilderAction = {\n type: string;\n ban_options?: BanOptions;\n flag_user_options?: FlagUserOptions;\n};\n\nexport type TextRuleParameters = {\n threshold: number;\n time_window: string;\n harm_labels?: string[];\n llm_harm_labels?: Record<string, string>;\n contains_url?: boolean;\n severity?: string;\n blocklist_match?: string[];\n};\n\nexport type ImageRuleParameters = {\n threshold: number;\n time_window: string;\n harm_labels: string[];\n};\n\nexport type VideoRuleParameters = {\n threshold: number;\n time_window: string;\n harm_labels: string[];\n};\n\nexport type UserRuleParameters = {\n max_age: string;\n};\n\nexport type ContentCountRuleParameters = {\n threshold: number;\n time_window: string;\n};\n\nexport type TextContentParameters = {\n harm_labels?: string[];\n llm_harm_labels?: Record<string, string>;\n contains_url?: boolean;\n severity?: string;\n blocklist_match?: string[];\n};\n\nexport type ImageContentParameters = {\n harm_labels: string[];\n};\n\nexport type VideoContentParameters = {\n harm_labels: string[];\n};\n\nexport type UserCreatedWithinParameters = {\n max_age: string;\n};\n\nexport type UserCustomPropertyParameters = {\n property_key: string;\n operator: string;\n expected_value: string;\n};\n\nexport type BanOptions = {\n duration: number;\n reason: string;\n shadow_ban: boolean;\n ip_ban: boolean;\n};\n\nexport type FlagUserOptions = {\n reason: string;\n};\n\nexport type QueryModerationRulesFilters = QueryFilters<{\n name?: string;\n team?: string;\n enabled?: boolean;\n rule_type?: string;\n created_at?: PrimitiveFilter<string>;\n updated_at?: PrimitiveFilter<string>;\n}>;\n\nexport type QueryModerationRulesSort = Array<\n Sort<'name' | 'enabled' | 'team' | 'created_at' | 'updated_at'>\n>;\n\nexport type QueryModerationRulesResponse = {\n rules: ModerationRule[];\n default_llm_labels: Record<string, string>;\n next?: string;\n prev?: string;\n};\n\nexport type UpsertModerationRuleResponse = {\n rule: ModerationRule;\n};\n\nexport type ModerationFlagOptions = {\n custom?: Record<string, unknown>;\n moderation_payload?: ModerationPayload;\n user_id?: string;\n};\n\nexport type ModerationMuteOptions = {\n timeout?: number;\n user_id?: string;\n};\nexport type GetUserModerationReportOptions = {\n create_user_if_not_exists?: boolean;\n include_user_blocks?: boolean;\n include_user_mutes?: boolean;\n};\n\nexport type AIState =\n | 'AI_STATE_ERROR'\n | 'AI_STATE_CHECKING_SOURCES'\n | 'AI_STATE_THINKING'\n | 'AI_STATE_GENERATING'\n | (string & {});\n\nexport type ModerationActionType =\n | 'flag'\n | 'shadow'\n | 'remove'\n | 'bounce'\n | 'bounce_flag'\n | 'bounce_remove';\n\nexport type AutomodRule = {\n action: ModerationActionType;\n label: string;\n threshold: number;\n};\n\nexport type BlockListRule = {\n action: ModerationActionType;\n name?: string;\n};\n\nexport type BlockListConfig = {\n enabled: boolean;\n rules: BlockListRule[];\n async?: boolean;\n};\n\nexport type AutomodToxicityConfig = {\n enabled: boolean;\n rules: AutomodRule[];\n async?: boolean;\n};\n\nexport type AutomodPlatformCircumventionConfig = {\n enabled: boolean;\n rules: AutomodRule[];\n async?: boolean;\n};\n\nexport type AutomodSemanticFiltersRule = {\n action: ModerationActionType;\n name: string;\n threshold: number;\n};\n\nexport type AutomodSemanticFiltersConfig = {\n enabled: boolean;\n rules: AutomodSemanticFiltersRule[];\n async?: boolean;\n};\n\nexport type AITextSeverityRule = {\n action: ModerationActionType;\n severity: 'low' | 'medium' | 'high' | 'critical';\n};\n\nexport type AITextRule = {\n label: string;\n action?: ModerationActionType;\n severity_rules?: AITextSeverityRule[];\n};\n\nexport type AITextConfig = {\n enabled: boolean;\n rules: AITextRule[];\n async?: boolean;\n profile?: string;\n severity_rules?: AITextSeverityRule[]; // Deprecated: use rules instead\n};\n\nexport type AIImageRule = {\n action: ModerationActionType;\n label: string;\n min_confidence?: number;\n};\n\nexport type AIImageConfig = {\n enabled: boolean;\n rules: AIImageRule[];\n async?: boolean;\n};\n\nexport type AIVideoRule = {\n action: ModerationActionType;\n label: string;\n min_confidence?: number;\n};\n\nexport type AIVideoConfig = {\n enabled: boolean;\n rules: AIVideoRule[];\n async?: boolean;\n};\n\nexport type VelocityFilterConfigRule = {\n action: 'flag' | 'shadow' | 'remove' | 'ban';\n ban_duration?: number;\n cascading_action?: 'flag' | 'shadow' | 'remove' | 'ban';\n cascading_threshold?: number;\n check_message_context?: boolean;\n fast_spam_threshold?: number;\n fast_spam_ttl?: number;\n ip_ban?: boolean;\n shadow_ban?: boolean;\n slow_spam_ban_duration?: number;\n slow_spam_threshold?: number;\n slow_spam_ttl?: number;\n};\n\nexport type VelocityFilterConfig = {\n cascading_actions: boolean;\n enabled: boolean;\n first_message_only: boolean;\n rules: VelocityFilterConfigRule[];\n async?: boolean;\n};\n\nexport type PromoteChannelParams = {\n channels: Array<Channel>;\n channelToMove: Channel;\n sort: ChannelSort;\n /**\n * If the index of the channel within `channels` list which is being moved upwards\n * (`channelToMove`) is known, you can supply it to skip extra calculation.\n */\n channelToMoveIndexWithinChannels?: number;\n};\n\n/**\n * An identifier containing information about the downstream SDK using stream-chat. It\n * is used to resolve the user agent.\n */\nexport type SdkIdentifier = {\n name: 'react' | 'react-native' | 'expo' | 'angular';\n version: string;\n};\n\n/**\n * An identifier containing information about the downstream device using stream-chat, if\n * available. Is used by the react-native SDKs to enrich the user agent further.\n */\nexport type DeviceIdentifier = { os: string; model?: string };\n\nexport type DraftResponse = {\n channel_cid: string;\n created_at: string;\n message: DraftMessage;\n channel?: ChannelResponse;\n parent_id?: string;\n parent_message?: MessageResponseBase;\n quoted_message?: MessageResponseBase;\n};\n\nexport type CreateDraftResponse = APIResponse & {\n draft: DraftResponse;\n};\n\nexport type GetDraftResponse = APIResponse & {\n draft: DraftResponse;\n};\n\nexport type QueryDraftsResponse = APIResponse & {\n drafts: DraftResponse[];\n} & Omit<Pager, 'limit'>;\n\nexport type DraftMessagePayload = PartializeKeys<DraftMessage, 'id'> & {\n user_id?: string;\n};\n\nexport type DraftMessage = {\n id: string;\n text: string;\n attachments?: Attachment[];\n custom?: {};\n html?: string;\n mentioned_users?: string[];\n mml?: string;\n parent_id?: string;\n poll_id?: string;\n quoted_message_id?: string;\n shared_location?: StaticLocationPayload | LiveLocationPayload; // todo: live-location verify if possible\n show_in_channel?: boolean;\n silent?: boolean;\n type?: MessageLabel;\n};\n\nexport type ActiveLiveLocationsAPIResponse = APIResponse & {\n active_live_locations: SharedLiveLocationResponse[];\n};\n\nexport type SharedLocationResponse = {\n channel_cid: string;\n created_at: string;\n created_by_device_id: string;\n end_at?: string;\n latitude: number;\n longitude: number;\n message_id: string;\n updated_at: string;\n user_id: string;\n};\n\nexport type SharedStaticLocationResponse = {\n channel_cid: string;\n created_at: string;\n created_by_device_id: string;\n latitude: number;\n longitude: number;\n message_id: string;\n updated_at: string;\n user_id: string;\n};\n\nexport type SharedLiveLocationResponse = {\n channel_cid: string;\n created_at: string;\n created_by_device_id: string;\n end_at: string;\n latitude: number;\n longitude: number;\n message_id: string;\n updated_at: string;\n user_id: string;\n};\n\nexport type UpdateLocationPayload = {\n message_id: string;\n created_by_device_id?: string;\n end_at?: string;\n latitude?: number;\n longitude?: number;\n user?: { id: string };\n user_id?: string;\n};\n\nexport type StaticLocationPayload = {\n created_by_device_id: string;\n latitude: number;\n longitude: number;\n message_id: string;\n};\n\nexport type LiveLocationPayload = {\n created_by_device_id: string;\n end_at: string;\n latitude: number;\n longitude: number;\n message_id: string;\n};\n\nexport type ThreadSort = ThreadSortBase | Array<ThreadSortBase>;\n\nexport type ThreadSortBase = {\n active_participant_count?: AscDesc;\n created_at?: AscDesc;\n last_message_at?: AscDesc;\n parent_message_id?: AscDesc;\n participant_count?: AscDesc;\n reply_count?: AscDesc;\n updated_at?: AscDesc;\n};\n\nexport type ThreadFilters = QueryFilters<\n {\n channel_cid?:\n | RequireOnlyOne<Pick<QueryFilter<string>, '$eq' | '$in'>>\n | PrimitiveFilter<string>;\n } & {\n parent_message_id?:\n | RequireOnlyOne<\n Pick<QueryFilter<ThreadResponse['parent_message_id']>, '$eq' | '$in'>\n >\n | PrimitiveFilter<ThreadResponse['parent_message_id']>;\n } & {\n created_by_user_id?:\n | RequireOnlyOne<\n Pick<QueryFilter<ThreadResponse['created_by_user_id']>, '$eq' | '$in'>\n >\n | PrimitiveFilter<ThreadResponse['created_by_user_id']>;\n } & {\n created_at?:\n | RequireOnlyOne<\n Pick<\n QueryFilter<ThreadResponse['created_at']>,\n '$eq' | '$gt' | '$lt' | '$gte' | '$lte'\n >\n >\n | PrimitiveFilter<ThreadResponse['created_at']>;\n } & {\n updated_at?:\n | RequireOnlyOne<\n Pick<\n QueryFilter<ThreadResponse['updated_at']>,\n '$eq' | '$gt' | '$lt' | '$gte' | '$lte'\n >\n >\n | PrimitiveFilter<ThreadResponse['updated_at']>;\n } & {\n last_message_at?:\n | RequireOnlyOne<\n Pick<\n QueryFilter<ThreadResponse['last_message_at']>,\n '$eq' | '$gt' | '$lt' | '$gte' | '$lte'\n >\n >\n | PrimitiveFilter<ThreadResponse['last_message_at']>;\n }\n>;\n\nexport type ReminderResponseBase = {\n channel_cid: string;\n created_at: string;\n message_id: string;\n updated_at: string;\n user_id: string;\n remind_at?: string;\n};\n\nexport type ReminderResponse = ReminderResponseBase & {\n user: UserResponse;\n message: MessageResponse;\n channel?: ChannelResponse;\n};\n\nexport type ReminderAPIResponse = APIResponse & {\n reminder: ReminderResponse;\n};\n\nexport type CreateReminderOptions = {\n messageId: string;\n remind_at?: string | null;\n user_id?: string;\n};\n\nexport type UpdateReminderOptions = CreateReminderOptions;\n\nexport type ReminderFilters = QueryFilters<{\n channel_cid?:\n | RequireOnlyOne<\n Pick<QueryFilter<ReminderResponseBase['channel_cid']>, '$eq' | '$in'>\n >\n | PrimitiveFilter<ReminderResponseBase['channel_cid']>;\n created_at?:\n | RequireOnlyOne<\n Pick<\n QueryFilter<ReminderResponseBase['created_at']>,\n '$eq' | '$gt' | '$lt' | '$gte' | '$lte'\n >\n >\n | PrimitiveFilter<ReminderResponseBase['created_at']>;\n message_id?:\n | RequireOnlyOne<Pick<QueryFilter<ReminderResponseBase['message_id']>, '$eq' | '$in'>>\n | PrimitiveFilter<ReminderResponseBase['message_id']>;\n remind_at?:\n | RequireOnlyOne<\n Pick<\n QueryFilter<ReminderResponseBase['remind_at']>,\n '$exists' | '$eq' | '$gt' | '$lt' | '$gte' | '$lte'\n >\n >\n | PrimitiveFilter<ReminderResponseBase['remind_at']>;\n user_id?:\n | RequireOnlyOne<Pick<QueryFilter<ReminderResponseBase['user_id']>, '$eq' | '$in'>>\n | PrimitiveFilter<ReminderResponseBase['user_id']>;\n}>;\n\nexport type ReminderSort =\n | Sort<\n Pick<\n ReminderResponseBase,\n 'channel_cid' | 'created_at' | 'remind_at' | 'updated_at'\n >\n >\n | Array<\n Sort<\n Pick<\n ReminderResponseBase,\n 'channel_cid' | 'created_at' | 'remind_at' | 'updated_at'\n >\n >\n >;\n\nexport type QueryRemindersOptions = Pager & {\n filter?: ReminderFilters;\n sort?: ReminderSort;\n};\n\nexport type QueryRemindersResponse = {\n reminders: ReminderResponse[];\n prev?: string;\n next?: string;\n};\n\nexport type HookType = 'webhook' | 'sqs' | 'sns' | 'pending_message';\n\nexport type EventHook = {\n id?: string;\n hook_type?: HookType;\n enabled?: boolean;\n product?: Product | 'all'; // optional, default is 'all'\n event_types?: Array<string>;\n webhook_url?: string;\n sqs_queue_url?: string;\n sqs_region?: string;\n sqs_auth_type?: string;\n sqs_key?: string;\n sqs_secret?: string;\n sqs_role_arn?: string;\n sns_topic_arn?: string;\n sns_region?: string;\n sns_auth_type?: string;\n sns_key?: string;\n sns_secret?: string;\n sns_role_arn?: string;\n\n // pending message config\n timeout_ms?: number;\n callback?: {\n mode: 'CALLBACK_MODE_NONE' | 'CALLBACK_MODE_REST' | 'CALLBACK_MODE_TWIRP';\n };\n\n delete?: boolean;\n created_at?: string;\n updated_at?: string;\n};\n", "import {\n PollComposerCompositionMiddlewareExecutor,\n PollComposerStateMiddlewareExecutor,\n VALID_MAX_VOTES_VALUE_REGEX,\n} from './middleware/pollComposer';\nimport { StateStore } from '../store';\nimport { VotingVisibility } from '../types';\nimport { generateUUIDv4 } from '../utils';\nimport type { MessageComposer } from './messageComposer';\nimport type {\n PollComposerFieldErrors,\n PollComposerState,\n UpdateFieldsData,\n} from './middleware/pollComposer';\n\nexport type PollComposerOptions = {\n composer: MessageComposer;\n};\n\nexport class PollComposer {\n readonly state: StateStore<PollComposerState>;\n readonly composer: MessageComposer;\n readonly compositionMiddlewareExecutor: PollComposerCompositionMiddlewareExecutor;\n readonly stateMiddlewareExecutor: PollComposerStateMiddlewareExecutor;\n\n constructor({ composer }: PollComposerOptions) {\n this.composer = composer;\n this.state = new StateStore<PollComposerState>(this.initialState);\n this.compositionMiddlewareExecutor = new PollComposerCompositionMiddlewareExecutor({\n composer,\n });\n this.stateMiddlewareExecutor = new PollComposerStateMiddlewareExecutor();\n }\n\n get initialState(): PollComposerState {\n return {\n data: {\n allow_answers: false,\n allow_user_suggested_options: false,\n description: '',\n enforce_unique_vote: true,\n id: generateUUIDv4(),\n max_votes_allowed: '',\n name: '',\n options: [{ id: generateUUIDv4(), text: '' }],\n user_id: this.composer.client.user?.id,\n voting_visibility: VotingVisibility.public,\n },\n errors: {},\n };\n }\n\n get allow_answers() {\n return this.state.getLatestValue().data.allow_answers;\n }\n get allow_user_suggested_options() {\n return this.state.getLatestValue().data.allow_user_suggested_options;\n }\n get description() {\n return this.state.getLatestValue().data.description;\n }\n get enforce_unique_vote() {\n return this.state.getLatestValue().data.enforce_unique_vote;\n }\n get id() {\n return this.state.getLatestValue().data.id;\n }\n get max_votes_allowed() {\n return this.state.getLatestValue().data.max_votes_allowed;\n }\n get name() {\n return this.state.getLatestValue().data.name;\n }\n get options() {\n return this.state.getLatestValue().data.options;\n }\n get user_id() {\n return this.state.getLatestValue().data.user_id;\n }\n get voting_visibility() {\n return this.state.getLatestValue().data.voting_visibility;\n }\n\n get canCreatePoll() {\n const { data, errors } = this.state.getLatestValue();\n const hasAtLeastOneNonEmptyOption =\n data.options.filter((o) => !!o.text.trim()).length > 0;\n const hasName = !!data.name;\n const maxVotesAllowedNumber = parseInt(\n data.max_votes_allowed?.match(VALID_MAX_VOTES_VALUE_REGEX)?.[0] || '',\n );\n\n const validMaxVotesAllowed =\n data.max_votes_allowed === '' ||\n (!!maxVotesAllowedNumber &&\n (2 <= maxVotesAllowedNumber || maxVotesAllowedNumber <= 10));\n\n return (\n hasAtLeastOneNonEmptyOption &&\n hasName &&\n validMaxVotesAllowed &&\n Object.values(errors).filter((errorText) => !!errorText).length === 0\n );\n }\n\n initState = () => {\n this.state.next(this.initialState);\n };\n\n /**\n * Updates specified fields and generates relevant errors\n * @param data\n * @param injectedFieldErrors - errors produced externally that will take precedence over the errors generated in the middleware chaing\n */\n // FIXME: change method params to a single object with the next major release\n updateFields = async (\n data: UpdateFieldsData,\n injectedFieldErrors?: PollComposerFieldErrors,\n ) => {\n const { state, status } = await this.stateMiddlewareExecutor.execute({\n eventName: 'handleFieldChange',\n initialValue: {\n nextState: { ...this.state.getLatestValue() },\n previousState: { ...this.state.getLatestValue() },\n targetFields: data,\n injectedFieldErrors,\n },\n });\n\n if (status === 'discard') return;\n this.state.next(state.nextState);\n };\n\n handleFieldBlur = async (field: keyof PollComposerState['data']) => {\n const result = await this.stateMiddlewareExecutor.execute({\n eventName: 'handleFieldBlur',\n initialValue: {\n nextState: { ...this.state.getLatestValue() },\n previousState: { ...this.state.getLatestValue() },\n targetFields: { [field]: this.state.getLatestValue().data[field] },\n },\n });\n\n if (result.status === 'discard') return;\n this.state.next(result.state.nextState);\n };\n\n compose = async () => {\n const { data, errors } = this.state.getLatestValue();\n const result = await this.compositionMiddlewareExecutor.execute({\n eventName: 'compose',\n initialValue: {\n data: {\n ...data,\n max_votes_allowed: data.max_votes_allowed\n ? parseInt(data.max_votes_allowed)\n : undefined,\n options: data.options\n ?.filter((o) => o.text.trim())\n .map((o) => ({ text: o.text })),\n },\n errors,\n },\n });\n if (result.status === 'discard') return;\n\n return result.state;\n };\n}\n", "import type { MiddlewareHandlerParams } from '../../../middleware';\nimport type { Attachment } from '../../../types';\nimport type { MessageComposer } from '../../messageComposer';\nimport type { LocalAttachment } from '../../types';\nimport type {\n MessageComposerMiddlewareState,\n MessageCompositionMiddleware,\n MessageDraftComposerMiddlewareValueState,\n MessageDraftCompositionMiddleware,\n} from './types';\n\nconst localAttachmentToAttachment = (localAttachment: LocalAttachment) => {\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n const { localMetadata, ...attachment } = localAttachment;\n return attachment as Attachment;\n};\n\nexport const createAttachmentsCompositionMiddleware = (\n composer: MessageComposer,\n): MessageCompositionMiddleware => ({\n id: 'stream-io/message-composer-middleware/attachments',\n handlers: {\n compose: ({\n state,\n next,\n discard,\n forward,\n }: MiddlewareHandlerParams<MessageComposerMiddlewareState>) => {\n const { attachmentManager } = composer;\n if (!attachmentManager) return forward();\n\n if (attachmentManager.uploadsInProgressCount > 0) {\n composer.client.notifications.addWarning({\n message: 'Wait until all attachments have uploaded',\n origin: {\n emitter: 'MessageComposer',\n context: { composer },\n },\n options: {\n type: 'validation:attachment:upload:in-progress',\n },\n });\n return discard();\n }\n\n const attachments = (state.message.attachments ?? []).concat(\n attachmentManager.successfulUploads.map(localAttachmentToAttachment),\n );\n\n // prevent introducing attachments array into the payload sent to the server\n if (!attachments.length) return forward();\n\n return next({\n ...state,\n localMessage: {\n ...state.localMessage,\n attachments,\n },\n message: {\n ...state.message,\n attachments,\n },\n });\n },\n },\n});\n\nexport const createDraftAttachmentsCompositionMiddleware = (\n composer: MessageComposer,\n): MessageDraftCompositionMiddleware => ({\n id: 'stream-io/message-composer-middleware/draft-attachments',\n handlers: {\n compose: ({\n state,\n next,\n forward,\n }: MiddlewareHandlerParams<MessageDraftComposerMiddlewareValueState>) => {\n const { attachmentManager } = composer;\n if (!attachmentManager) return forward();\n\n const successfulUploads = attachmentManager.successfulUploads;\n const attachments = successfulUploads.length\n ? (state.draft.attachments ?? []).concat(\n successfulUploads.map(localAttachmentToAttachment),\n )\n : undefined;\n\n return next({\n ...state,\n draft: {\n ...state.draft,\n attachments,\n },\n });\n },\n },\n});\n", "import type { MiddlewareHandlerParams } from '../../../middleware';\nimport { formatMessage, toUpdatedMessagePayload } from '../../../utils';\nimport type { MessageComposer } from '../../messageComposer';\nimport type {\n MessageComposerMiddlewareState,\n MessageCompositionMiddleware,\n} from './types';\n\nexport const createCompositionDataCleanupMiddleware = (\n composer: MessageComposer,\n): MessageCompositionMiddleware => ({\n id: 'stream-io/message-composer-middleware/data-cleanup',\n handlers: {\n compose: ({\n state,\n next,\n }: MiddlewareHandlerParams<MessageComposerMiddlewareState>) => {\n const common = {\n type: composer.editedMessage?.type ?? 'regular',\n };\n\n const editedMessagePayloadToBeSent = composer.editedMessage\n ? toUpdatedMessagePayload(composer.editedMessage)\n : undefined;\n\n return next({\n ...state,\n localMessage: formatMessage({\n ...composer.editedMessage,\n ...state.localMessage,\n ...common,\n }),\n message: {\n ...editedMessagePayloadToBeSent,\n ...state.message,\n ...common,\n },\n sendOptions:\n composer.editedMessage && state.sendOptions?.skip_enrich_url\n ? { skip_enrich_url: state.sendOptions?.skip_enrich_url }\n : state.sendOptions,\n });\n },\n },\n});\n", "import type { MiddlewareHandlerParams } from '../../../middleware';\nimport type { MessageComposer } from '../../messageComposer';\nimport type {\n MessageComposerMiddlewareState,\n MessageCompositionMiddleware,\n MessageDraftComposerMiddlewareValueState,\n MessageDraftCompositionMiddleware,\n} from './types';\n\nexport const createCustomDataCompositionMiddleware = (\n composer: MessageComposer,\n): MessageCompositionMiddleware => ({\n id: 'stream-io/message-composer-middleware/custom-data',\n handlers: {\n compose: ({\n state,\n next,\n forward,\n }: MiddlewareHandlerParams<MessageComposerMiddlewareState>) => {\n const data = composer.customDataManager.customMessageData;\n if (!data) return forward();\n\n return next({\n ...state,\n localMessage: {\n ...state.localMessage,\n ...data,\n },\n message: {\n ...state.message,\n ...data,\n },\n });\n },\n },\n});\n\nexport const createDraftCustomDataCompositionMiddleware = (\n composer: MessageComposer,\n): MessageDraftCompositionMiddleware => ({\n id: 'stream-io/message-composer-middleware/draft-custom-data',\n handlers: {\n compose: ({\n state,\n next,\n forward,\n }: MiddlewareHandlerParams<MessageDraftComposerMiddlewareValueState>) => {\n const data = composer.customDataManager.customMessageData;\n if (!data) return forward();\n\n return next({\n ...state,\n draft: {\n ...state.draft,\n ...data,\n },\n });\n },\n },\n});\n", "import { textIsEmpty } from '../../textComposer';\nimport type {\n MessageComposerMiddlewareState,\n MessageCompositionMiddleware,\n MessageDraftComposerMiddlewareValueState,\n MessageDraftCompositionMiddleware,\n} from './types';\nimport type { MessageComposer } from '../../messageComposer';\nimport type { MiddlewareHandlerParams } from '../../../middleware';\n\nexport const createCompositionValidationMiddleware = (\n composer: MessageComposer,\n): MessageCompositionMiddleware => ({\n id: 'stream-io/message-composer-middleware/data-validation',\n handlers: {\n compose: async ({\n state,\n discard,\n forward,\n }: MiddlewareHandlerParams<MessageComposerMiddlewareState>) => {\n const { maxLengthOnSend } = composer.config.text ?? {};\n const inputText = state.message.text ?? '';\n\n const hasExceededMaxLength =\n typeof maxLengthOnSend === 'number' && inputText.length > maxLengthOnSend;\n\n if (composer.compositionIsEmpty || hasExceededMaxLength) {\n return await discard();\n }\n\n return await forward();\n },\n },\n});\n\nexport const createDraftCompositionValidationMiddleware = (\n composer: MessageComposer,\n): MessageDraftCompositionMiddleware => ({\n id: 'stream-io/message-composer-middleware/draft-data-validation',\n handlers: {\n compose: async ({\n state,\n discard,\n forward,\n }: MiddlewareHandlerParams<MessageDraftComposerMiddlewareValueState>) => {\n const hasData =\n !textIsEmpty(state.draft.text ?? '') ||\n state.draft.attachments?.length ||\n state.draft.poll_id ||\n state.draft.quoted_message_id;\n\n const shouldCreateDraft = composer.lastChangeOriginIsLocal && hasData;\n\n if (!shouldCreateDraft) {\n return await discard();\n }\n\n return await forward();\n },\n },\n});\n", "import { LinkPreviewsManager } from '../..';\nimport type { MiddlewareHandlerParams } from '../../../middleware';\nimport type { Attachment } from '../../../types';\nimport type { MessageComposer } from '../../messageComposer';\nimport type {\n MessageComposerMiddlewareState,\n MessageCompositionMiddleware,\n MessageDraftComposerMiddlewareValueState,\n MessageDraftCompositionMiddleware,\n} from './types';\n\nexport const createLinkPreviewsCompositionMiddleware = (\n composer: MessageComposer,\n): MessageCompositionMiddleware => ({\n id: 'stream-io/message-composer-middleware/link-previews',\n handlers: {\n compose: ({\n state,\n next,\n forward,\n }: MiddlewareHandlerParams<MessageComposerMiddlewareState>) => {\n const { linkPreviewsManager } = composer;\n if (!linkPreviewsManager) return forward();\n\n linkPreviewsManager.cancelURLEnrichment();\n const someLinkPreviewsLoading = linkPreviewsManager.loadingPreviews.length > 0;\n const someLinkPreviewsDismissed = linkPreviewsManager.dismissedPreviews.length > 0;\n const linkPreviews =\n linkPreviewsManager.loadingPreviews.length > 0\n ? []\n : linkPreviewsManager.loadedPreviews.map((preview) =>\n LinkPreviewsManager.getPreviewData(preview),\n );\n\n const attachments: Attachment[] = (state.message.attachments ?? []).concat(\n linkPreviews,\n );\n\n // prevent introducing attachments array into the payload sent to the server\n if (!attachments.length) return forward();\n\n const sendOptions = { ...state.sendOptions };\n const skip_enrich_url =\n (!someLinkPreviewsLoading && linkPreviews.length > 0) ||\n someLinkPreviewsDismissed;\n if (skip_enrich_url) {\n sendOptions.skip_enrich_url = true;\n }\n\n return next({\n ...state,\n message: {\n ...state.message,\n attachments,\n },\n localMessage: {\n ...state.localMessage,\n attachments,\n },\n sendOptions,\n });\n },\n },\n});\n\nexport const createDraftLinkPreviewsCompositionMiddleware = (\n composer: MessageComposer,\n): MessageDraftCompositionMiddleware => ({\n id: 'stream-io/message-composer-middleware/draft-link-previews',\n handlers: {\n compose: ({\n state,\n next,\n forward,\n }: MiddlewareHandlerParams<MessageDraftComposerMiddlewareValueState>) => {\n const { linkPreviewsManager } = composer;\n if (!linkPreviewsManager) return forward();\n\n linkPreviewsManager.cancelURLEnrichment();\n const linkPreviews = linkPreviewsManager.loadedPreviews.map((preview) =>\n LinkPreviewsManager.getPreviewData(preview),\n );\n\n if (!linkPreviews.length) return forward();\n\n return next({\n ...state,\n draft: {\n ...state.draft,\n attachments: (state.draft.attachments ?? []).concat(linkPreviews),\n },\n });\n },\n },\n});\n", "import type {\n MessageComposerMiddlewareState,\n MessageCompositionMiddleware,\n MessageDraftComposerMiddlewareValueState,\n MessageDraftCompositionMiddleware,\n} from './types';\nimport type { MessageComposer } from '../../messageComposer';\nimport type { MiddlewareHandlerParams } from '../../../middleware';\n\nexport const createTextComposerCompositionMiddleware = (\n composer: MessageComposer,\n): MessageCompositionMiddleware => ({\n id: 'stream-io/message-composer-middleware/text-composition',\n handlers: {\n compose: ({\n state,\n next,\n forward,\n }: MiddlewareHandlerParams<MessageComposerMiddlewareState>) => {\n if (!composer.textComposer) return forward();\n const { mentionedUsers, text } = composer.textComposer;\n // Instead of checking if a user is still mentioned every time the text changes,\n // just filter out non-mentioned users before submit, which is cheaper\n // and allows users to easily undo any accidental deletion\n const mentioned_users = Array.from(\n new Set(\n mentionedUsers.filter(\n ({ id, name }) => text.includes(`@${id}`) || text.includes(`@${name}`),\n ),\n ),\n );\n\n // prevent introducing text and mentioned_users array into the payload sent to the server\n if (!text && mentioned_users.length === 0) return forward();\n\n return next({\n ...state,\n localMessage: {\n ...state.localMessage,\n mentioned_users,\n text,\n },\n message: {\n ...state.message,\n mentioned_users: mentioned_users.map((u) => u.id),\n text,\n },\n });\n },\n },\n});\n\nexport const createDraftTextComposerCompositionMiddleware = (\n composer: MessageComposer,\n): MessageDraftCompositionMiddleware => ({\n id: 'stream-io/message-composer-middleware/draft-text-composition',\n handlers: {\n compose: ({\n state,\n next,\n forward,\n }: MiddlewareHandlerParams<MessageDraftComposerMiddlewareValueState>) => {\n if (!composer.textComposer) return forward();\n const { maxLengthOnSend } = composer.config.text ?? {};\n const { mentionedUsers, text: inputText } = composer.textComposer;\n // Instead of checking if a user is still mentioned every time the text changes,\n // just filter out non-mentioned users before submit, which is cheaper\n // and allows users to easily undo any accidental deletion\n const mentioned_users = mentionedUsers.length\n ? Array.from(\n new Set(\n mentionedUsers.filter(\n ({ id, name }) =>\n inputText.includes(`@${id}`) || inputText.includes(`@${name}`),\n ),\n ),\n )\n : undefined;\n\n const text =\n typeof maxLengthOnSend === 'number' && inputText.length > maxLengthOnSend\n ? inputText.slice(0, maxLengthOnSend)\n : inputText;\n\n return next({\n ...state,\n draft: {\n ...state.draft,\n mentioned_users: mentioned_users?.map((u) => u.id),\n text,\n },\n });\n },\n },\n});\n", "import type {\n MessageComposerMiddlewareState,\n MessageCompositionMiddleware,\n MessageDraftComposerMiddlewareValueState,\n MessageDraftCompositionMiddleware,\n} from './types';\nimport type { MessageComposer } from '../../messageComposer';\nimport type { LocalMessage, LocalMessageBase } from '../../../types';\nimport type { MiddlewareHandlerParams } from '../../../middleware';\n\nexport const createMessageComposerStateCompositionMiddleware = (\n composer: MessageComposer,\n): MessageCompositionMiddleware => ({\n id: 'stream-io/message-composer-middleware/own-state',\n handlers: {\n compose: ({\n state,\n next,\n }: MiddlewareHandlerParams<MessageComposerMiddlewareState>) => {\n const payload: Pick<\n LocalMessage,\n 'poll_id' | 'quoted_message_id' | 'show_in_channel'\n > = {};\n if (composer.quotedMessage) {\n payload.quoted_message_id = composer.quotedMessage.id;\n }\n if (composer.pollId) {\n payload.poll_id = composer.pollId;\n }\n\n if (composer.showReplyInChannel) {\n payload.show_in_channel = true;\n }\n\n return next({\n ...state,\n localMessage: {\n ...state.localMessage,\n ...payload,\n quoted_message: (composer.quotedMessage as LocalMessageBase) ?? undefined,\n },\n message: {\n ...state.message,\n ...payload,\n },\n });\n },\n },\n});\n\nexport const createDraftMessageComposerStateCompositionMiddleware = (\n composer: MessageComposer,\n): MessageDraftCompositionMiddleware => ({\n id: 'stream-io/message-composer-middleware/draft-own-state',\n handlers: {\n compose: ({\n state,\n next,\n }: MiddlewareHandlerParams<MessageDraftComposerMiddlewareValueState>) => {\n const payload: Pick<\n LocalMessage,\n 'poll_id' | 'quoted_message_id' | 'show_in_channel'\n > = {};\n if (composer.quotedMessage) {\n payload.quoted_message_id = composer.quotedMessage.id;\n }\n if (composer.pollId) {\n payload.poll_id = composer.pollId;\n }\n\n if (composer.showReplyInChannel) {\n payload.show_in_channel = true;\n }\n\n return next({\n ...state,\n draft: {\n ...state.draft,\n ...payload,\n },\n });\n },\n },\n});\n", "import type { MessageComposer } from '../../messageComposer';\nimport type {\n MessageComposerMiddlewareState,\n MessageCompositionMiddleware,\n} from './types';\nimport type { MiddlewareHandlerParams } from '../../../middleware';\nimport type { OwnUserResponse } from '../../../types';\n\nexport const createUserDataInjectionMiddleware = (\n composer: MessageComposer,\n): MessageCompositionMiddleware => ({\n id: 'stream-io/message-composer-middleware/user-data-injection',\n handlers: {\n compose: ({\n state,\n next,\n forward,\n }: MiddlewareHandlerParams<MessageComposerMiddlewareState>) => {\n if (!composer.client.user) {\n return forward();\n }\n // Exclude the following properties from client.user as they can be large objects\n // that provide no value for localMessage (and will never exist within message.user).\n // This way we make sure that our localMessage is enriched with data as close as\n // possible to the actual user.\n // The reason why we need to explicitly cast is because OwnUserResponse only takes\n // precedence after we connectUser the first time and we get the connection health\n // check event. Due to how liberal the type of client.user is, we have to do it this\n // way to maintain type safety.\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n const { channel_mutes, devices, mutes, ...messageUser } = composer.client\n .user as OwnUserResponse;\n return next({\n ...state,\n localMessage: {\n ...state.localMessage,\n user: messageUser,\n user_id: messageUser.id,\n },\n });\n },\n },\n});\n", "import type {\n MessageComposerMiddlewareState,\n MessageCompositionMiddleware,\n} from './types';\nimport type { MessageComposer } from '../../messageComposer';\nimport type { MiddlewareHandlerParams } from '../../../middleware';\nimport type { LocalMessage } from '../../../types';\n\nconst pollLocalMessageNullifiedFields: Pick<\n LocalMessage,\n 'attachments' | 'mentioned_users' | 'parent_id' | 'quoted_message' | 'text'\n> = {\n attachments: [],\n mentioned_users: [],\n parent_id: undefined,\n quoted_message: undefined,\n text: '',\n};\n\nexport const createPollOnlyCompositionMiddleware = (\n composer: MessageComposer,\n): MessageCompositionMiddleware => ({\n id: 'stream-io/message-composer-middleware/poll-only',\n handlers: {\n compose: ({\n state,\n complete,\n forward,\n }: MiddlewareHandlerParams<MessageComposerMiddlewareState>) => {\n const pollId = composer.pollId;\n const isEditingMessage = !!composer.editedMessage;\n const isComposingThreadReply = !!composer.threadId;\n if (!pollId || isComposingThreadReply || isEditingMessage) return forward();\n\n return complete({\n ...state,\n localMessage: {\n ...state.localMessage,\n ...pollLocalMessageNullifiedFields,\n poll_id: pollId,\n },\n message: {\n id: state.localMessage.id,\n poll_id: pollId,\n },\n });\n },\n },\n});\n", "import type { MiddlewareHandlerParams } from '../../../middleware';\nimport type { MessageComposer } from '../../messageComposer';\nimport type {\n MessageComposerMiddlewareState,\n MessageCompositionMiddleware,\n} from './types';\n\nexport const createSharedLocationCompositionMiddleware = (\n composer: MessageComposer,\n): MessageCompositionMiddleware => ({\n id: 'stream-io/message-composer-middleware/shared-location',\n handlers: {\n compose: ({\n state,\n next,\n forward,\n }: MiddlewareHandlerParams<MessageComposerMiddlewareState>) => {\n const { locationComposer } = composer;\n const location = locationComposer.validLocation;\n if (!locationComposer || !location || !composer.client.user) return forward();\n const timestamp = new Date().toISOString();\n\n return next({\n ...state,\n localMessage: {\n ...state.localMessage,\n shared_location: {\n ...location,\n channel_cid: composer.channel.cid,\n created_at: timestamp,\n updated_at: timestamp,\n user_id: composer.client.user.id,\n },\n },\n message: {\n ...state.message,\n shared_location: location,\n },\n });\n },\n },\n});\n", "import { MiddlewareExecutor } from '../../../middleware';\nimport {\n createDraftTextComposerCompositionMiddleware,\n createTextComposerCompositionMiddleware,\n} from './textComposer';\nimport {\n createAttachmentsCompositionMiddleware,\n createDraftAttachmentsCompositionMiddleware,\n} from './attachments';\nimport {\n createDraftLinkPreviewsCompositionMiddleware,\n createLinkPreviewsCompositionMiddleware,\n} from './linkPreviews';\nimport {\n createDraftMessageComposerStateCompositionMiddleware,\n createMessageComposerStateCompositionMiddleware,\n} from './messageComposerState';\nimport {\n createCompositionValidationMiddleware,\n createDraftCompositionValidationMiddleware,\n} from './compositionValidation';\nimport { createCompositionDataCleanupMiddleware } from './cleanData';\nimport type {\n MessageComposerMiddlewareExecutorOptions,\n MessageComposerMiddlewareState,\n MessageDraftComposerMiddlewareExecutorOptions,\n MessageDraftComposerMiddlewareValueState,\n} from './types';\nimport {\n createCustomDataCompositionMiddleware,\n createDraftCustomDataCompositionMiddleware,\n} from './customData';\nimport { createUserDataInjectionMiddleware } from './userDataInjection';\nimport { createPollOnlyCompositionMiddleware } from './pollOnly';\nimport { createSharedLocationCompositionMiddleware } from './sharedLocation';\n\nexport class MessageComposerMiddlewareExecutor extends MiddlewareExecutor<\n MessageComposerMiddlewareState,\n 'compose'\n> {\n constructor({ composer }: MessageComposerMiddlewareExecutorOptions) {\n super();\n // todo: document how to add custom data to a composed message using middleware\n // or adding custom composer components (apart from AttachmentsManager, TextComposer etc.)\n this.use([\n createUserDataInjectionMiddleware(composer),\n createPollOnlyCompositionMiddleware(composer),\n createTextComposerCompositionMiddleware(composer),\n createAttachmentsCompositionMiddleware(composer),\n createLinkPreviewsCompositionMiddleware(composer),\n createSharedLocationCompositionMiddleware(composer),\n createMessageComposerStateCompositionMiddleware(composer),\n createCustomDataCompositionMiddleware(composer),\n createCompositionValidationMiddleware(composer),\n createCompositionDataCleanupMiddleware(composer),\n ]);\n }\n}\n\nexport class MessageDraftComposerMiddlewareExecutor extends MiddlewareExecutor<\n MessageDraftComposerMiddlewareValueState,\n 'compose'\n> {\n constructor({ composer }: MessageDraftComposerMiddlewareExecutorOptions) {\n super();\n // todo: document how to add custom data to a composed message using middleware\n // or adding custom composer components (apart from AttachmentsManager, TextComposer etc.)\n this.use([\n createDraftTextComposerCompositionMiddleware(composer),\n createDraftAttachmentsCompositionMiddleware(composer),\n createDraftLinkPreviewsCompositionMiddleware(composer),\n createDraftMessageComposerStateCompositionMiddleware(composer),\n createDraftCustomDataCompositionMiddleware(composer),\n createDraftCompositionValidationMiddleware(composer),\n ]);\n }\n}\n", "import type { MessageComposer } from '../../messageComposer';\nimport type {\n MessageComposerMiddlewareState,\n MessageCompositionMiddleware,\n MessageDraftComposerMiddlewareValueState,\n MessageDraftCompositionMiddleware,\n} from '../messageComposer/types';\nimport type { MiddlewareHandlerParams } from '../../../middleware';\n\nexport const createCommandInjectionMiddleware = (\n composer: MessageComposer,\n): MessageCompositionMiddleware => ({\n handlers: {\n compose: ({\n forward,\n next,\n state,\n }: MiddlewareHandlerParams<MessageComposerMiddlewareState>) => {\n const command = composer.textComposer.command;\n if (!command) {\n return forward();\n }\n const { text } = state.localMessage;\n\n const injection = `/${command?.name}`;\n const enrichedText = `${injection} ${text}`;\n\n return next({\n ...state,\n localMessage: {\n ...state.localMessage,\n text: enrichedText,\n },\n message: {\n ...state.message,\n text: enrichedText,\n },\n });\n },\n },\n id: 'stream-io/message-composer-middleware/command-string-injection',\n});\n\nexport const createDraftCommandInjectionMiddleware = (\n composer: MessageComposer,\n): MessageDraftCompositionMiddleware => ({\n handlers: {\n compose: ({\n forward,\n next,\n state,\n }: MiddlewareHandlerParams<MessageDraftComposerMiddlewareValueState>) => {\n const command = composer.textComposer.command;\n if (!command) {\n return forward();\n }\n const { text } = state.draft;\n\n const injection = `/${command?.name}`;\n const enrichedText = `${injection} ${text}`;\n\n return next({\n ...state,\n draft: {\n ...state.draft,\n text: enrichedText,\n },\n });\n },\n },\n id: 'stream-io/message-composer-middleware/draft-command-string-injection',\n});\n", "import type { Middleware } from '../../../middleware';\nimport type { TextComposerMiddlewareExecutorState } from './TextComposerMiddlewareExecutor';\n\nexport type PreCommandMiddleware = Middleware<\n TextComposerMiddlewareExecutorState,\n 'onChange' | 'onSuggestionItemSelect'\n>;\n\nexport const createActiveCommandGuardMiddleware = (): PreCommandMiddleware => ({\n handlers: {\n onChange: ({ complete, forward, state }) => {\n if (state.command) {\n return complete(state);\n }\n return forward();\n },\n onSuggestionItemSelect: ({ forward }) => forward(),\n },\n id: 'stream-io/text-composer/active-command-guard',\n});\n", "import { StateStore } from '../store';\nimport { debounce, type DebouncedFunc } from '../utils';\nimport type {\n QueryReturnValue,\n SearchSourceOptions,\n SearchSourceState,\n SearchSourceType,\n} from './types';\n\nexport type DebounceOptions = {\n debounceMs: number;\n};\ntype DebouncedExecQueryFunction = DebouncedFunc<(searchString?: string) => Promise<void>>;\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\ninterface ISearchSource<T = any> {\n activate(): void;\n\n canExecuteQuery(newSearchString?: string): boolean;\n\n deactivate(): void;\n\n readonly hasNext: boolean;\n readonly hasResults: boolean;\n readonly initialState: SearchSourceState<T>;\n readonly isActive: boolean;\n readonly isLoading: boolean;\n readonly items: T[] | undefined;\n readonly lastQueryError: Error | undefined;\n readonly next: string | undefined | null;\n readonly offset: number | undefined;\n\n resetState(): void;\n\n readonly searchQuery: string;\n\n readonly state: StateStore<SearchSourceState<T>>;\n readonly type: SearchSourceType;\n}\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport interface SearchSource<T = any> extends ISearchSource<T> {\n cancelScheduledQuery(): void;\n setDebounceOptions(options: DebounceOptions): void;\n search(text?: string): Promise<void> | undefined;\n}\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport interface SearchSourceSync<T = any> extends ISearchSource<T> {\n cancelScheduledQuery(): void;\n setDebounceOptions(options: DebounceOptions): void;\n search(text?: string): void;\n}\n\nconst DEFAULT_SEARCH_SOURCE_OPTIONS: Required<SearchSourceOptions> = {\n debounceMs: 300,\n pageSize: 10,\n} as const;\n\nabstract class BaseSearchSourceBase<T> implements ISearchSource<T> {\n state: StateStore<SearchSourceState<T>>;\n pageSize: number;\n abstract readonly type: SearchSourceType;\n\n protected constructor(options?: SearchSourceOptions) {\n const { pageSize } = { ...DEFAULT_SEARCH_SOURCE_OPTIONS, ...options };\n this.pageSize = pageSize;\n this.state = new StateStore<SearchSourceState<T>>(this.initialState);\n }\n\n get lastQueryError() {\n return this.state.getLatestValue().lastQueryError;\n }\n\n get hasNext() {\n return this.state.getLatestValue().hasNext;\n }\n\n get hasResults() {\n return Array.isArray(this.state.getLatestValue().items);\n }\n\n get isActive() {\n return this.state.getLatestValue().isActive;\n }\n\n get isLoading() {\n return this.state.getLatestValue().isLoading;\n }\n\n get initialState() {\n return {\n hasNext: true,\n isActive: false,\n isLoading: false,\n items: undefined,\n lastQueryError: undefined,\n next: undefined,\n offset: 0,\n searchQuery: '',\n };\n }\n\n get items() {\n return this.state.getLatestValue().items;\n }\n\n get next() {\n return this.state.getLatestValue().next;\n }\n\n get offset() {\n return this.state.getLatestValue().offset;\n }\n\n get searchQuery() {\n return this.state.getLatestValue().searchQuery;\n }\n\n activate = () => {\n if (this.isActive) return;\n this.state.partialNext({ isActive: true });\n };\n\n deactivate = () => {\n if (!this.isActive) return;\n this.state.partialNext({ isActive: false });\n };\n\n canExecuteQuery = (newSearchString?: string) => {\n const hasNewSearchQuery = typeof newSearchString !== 'undefined';\n const searchString = newSearchString ?? this.searchQuery;\n return !!(\n this.isActive &&\n !this.isLoading &&\n (this.hasNext || hasNewSearchQuery) &&\n searchString\n );\n };\n\n protected getStateBeforeFirstQuery(newSearchString: string): SearchSourceState<T> {\n return {\n ...this.initialState,\n isActive: this.isActive,\n isLoading: true,\n searchQuery: newSearchString,\n };\n }\n\n protected getStateAfterQuery(\n stateUpdate: Partial<SearchSourceState<T>>,\n isFirstPage: boolean,\n ): SearchSourceState<T> {\n const current = this.state.getLatestValue();\n return {\n ...current,\n lastQueryError: undefined, // reset lastQueryError that can be overridden by the stateUpdate\n ...stateUpdate,\n isLoading: false,\n items: isFirstPage\n ? stateUpdate.items\n : [...(this.items ?? []), ...(stateUpdate.items || [])],\n };\n }\n\n protected prepareStateForQuery(newSearchString?: string) {\n const hasNewSearchQuery = typeof newSearchString !== 'undefined';\n const searchString = newSearchString ?? this.searchQuery;\n\n if (hasNewSearchQuery) {\n this.state.next(this.getStateBeforeFirstQuery(newSearchString ?? ''));\n } else {\n this.state.partialNext({ isLoading: true });\n }\n\n return { searchString, hasNewSearchQuery };\n }\n\n protected updatePaginationStateFromQuery(result: QueryReturnValue<T>) {\n const { items, next } = result;\n\n const stateUpdate: Partial<SearchSourceState<T>> = {};\n if (Object.prototype.hasOwnProperty.call(result, 'next')) {\n stateUpdate.next = next;\n stateUpdate.hasNext = !!next;\n } else {\n stateUpdate.offset = (this.offset ?? 0) + items.length;\n stateUpdate.hasNext = items.length === this.pageSize;\n }\n\n return stateUpdate;\n }\n\n resetState() {\n this.state.next(this.initialState);\n }\n\n resetStateAndActivate() {\n this.resetState();\n this.activate();\n }\n}\n\nexport abstract class BaseSearchSource<T>\n extends BaseSearchSourceBase<T>\n implements SearchSource<T>\n{\n protected searchDebounced!: DebouncedExecQueryFunction;\n\n constructor(options?: SearchSourceOptions) {\n const { debounceMs } = { ...DEFAULT_SEARCH_SOURCE_OPTIONS, ...options };\n super(options);\n this.setDebounceOptions({ debounceMs });\n }\n\n protected abstract query(searchQuery: string): Promise<QueryReturnValue<T>>;\n\n protected abstract filterQueryResults(items: T[]): T[] | Promise<T[]>;\n\n setDebounceOptions = ({ debounceMs }: DebounceOptions) => {\n this.searchDebounced = debounce(this.executeQuery.bind(this), debounceMs);\n };\n\n async executeQuery(newSearchString?: string) {\n if (!this.canExecuteQuery(newSearchString)) return;\n\n const { hasNewSearchQuery, searchString } =\n this.prepareStateForQuery(newSearchString);\n\n let stateUpdate: Partial<SearchSourceState<T>> = {};\n try {\n const results = await this.query(searchString);\n if (!results) return;\n\n const { items } = results;\n stateUpdate = this.updatePaginationStateFromQuery(results);\n stateUpdate.items = await this.filterQueryResults(items);\n } catch (e) {\n stateUpdate.lastQueryError = e as Error;\n } finally {\n this.state.next(this.getStateAfterQuery(stateUpdate, hasNewSearchQuery));\n }\n }\n\n search = (searchQuery?: string) => this.searchDebounced(searchQuery);\n\n cancelScheduledQuery() {\n this.searchDebounced.cancel();\n }\n}\n\nexport abstract class BaseSearchSourceSync<T>\n extends BaseSearchSourceBase<T>\n implements SearchSourceSync<T>\n{\n protected searchDebounced!: DebouncedExecQueryFunction;\n\n constructor(options?: SearchSourceOptions) {\n const { debounceMs } = { ...DEFAULT_SEARCH_SOURCE_OPTIONS, ...options };\n super(options);\n this.setDebounceOptions({ debounceMs });\n }\n\n protected abstract query(searchQuery: string): QueryReturnValue<T>;\n\n protected abstract filterQueryResults(items: T[]): T[];\n\n setDebounceOptions = ({ debounceMs }: DebounceOptions) => {\n this.searchDebounced = debounce(this.executeQuery.bind(this), debounceMs);\n };\n\n executeQuery(newSearchString?: string) {\n if (!this.canExecuteQuery(newSearchString)) return;\n\n const { hasNewSearchQuery, searchString } =\n this.prepareStateForQuery(newSearchString);\n\n let stateUpdate: Partial<SearchSourceState<T>> = {};\n try {\n const results = this.query(searchString);\n if (!results) return;\n\n const { items } = results;\n stateUpdate = this.updatePaginationStateFromQuery(results);\n stateUpdate.items = this.filterQueryResults(items);\n } catch (e) {\n stateUpdate.lastQueryError = e as Error;\n } finally {\n this.state.next(this.getStateAfterQuery(stateUpdate, hasNewSearchQuery));\n }\n }\n\n search = (searchQuery?: string) => this.searchDebounced(searchQuery);\n\n cancelScheduledQuery() {\n this.searchDebounced.cancel();\n }\n}\n", "import { StateStore } from '../store';\nimport type { MessageResponse } from '../types';\nimport type { SearchSource } from './BaseSearchSource';\n\nexport type SearchControllerState = {\n isActive: boolean;\n searchQuery: string;\n sources: SearchSource[];\n};\n\nexport type InternalSearchControllerState = {\n // FIXME: focusedMessage should live in a MessageListController class that does not exist yet.\n // This state prop should be then removed\n focusedMessage?: MessageResponse;\n};\n\nexport type SearchControllerConfig = {\n // The controller will make sure there is always exactly one active source. Enabled by default.\n keepSingleActiveSource: boolean;\n};\n\nexport type SearchControllerOptions = {\n config?: Partial<SearchControllerConfig>;\n sources?: SearchSource[];\n};\n\nexport class SearchController {\n /**\n * Not intended for direct use by integrators, might be removed without notice resulting in\n * broken integrations.\n */\n _internalState: StateStore<InternalSearchControllerState>;\n state: StateStore<SearchControllerState>;\n config: SearchControllerConfig;\n\n constructor({ config, sources }: SearchControllerOptions = {}) {\n this.state = new StateStore<SearchControllerState>({\n isActive: false,\n searchQuery: '',\n sources: sources ?? [],\n });\n this._internalState = new StateStore<InternalSearchControllerState>({});\n this.config = { keepSingleActiveSource: true, ...config };\n }\n get hasNext() {\n return this.sources.some((source) => source.hasNext);\n }\n\n get sources() {\n return this.state.getLatestValue().sources;\n }\n\n get activeSources() {\n return this.state.getLatestValue().sources.filter((s) => s.isActive);\n }\n\n get isActive() {\n return this.state.getLatestValue().isActive;\n }\n\n get searchQuery() {\n return this.state.getLatestValue().searchQuery;\n }\n\n get searchSourceTypes(): Array<SearchSource['type']> {\n return this.sources.map((s) => s.type);\n }\n\n addSource = (source: SearchSource) => {\n this.state.partialNext({\n sources: [...this.sources, source],\n });\n };\n\n getSource = (sourceType: SearchSource['type']) =>\n this.sources.find((s) => s.type === sourceType);\n\n removeSource = (sourceType: SearchSource['type']) => {\n const newSources = this.sources.filter((s) => s.type !== sourceType);\n if (newSources.length === this.sources.length) return;\n this.state.partialNext({ sources: newSources });\n };\n\n activateSource = (sourceType: SearchSource['type']) => {\n const source = this.getSource(sourceType);\n if (!source || source.isActive) return;\n if (this.config.keepSingleActiveSource) {\n this.sources.forEach((s) => {\n if (s.type !== sourceType) {\n s.deactivate();\n }\n });\n }\n source.activate();\n this.state.partialNext({ sources: [...this.sources] });\n };\n\n deactivateSource = (sourceType: SearchSource['type']) => {\n const source = this.getSource(sourceType);\n if (!source?.isActive) return;\n if (this.activeSources.length === 1) return;\n source.deactivate();\n this.state.partialNext({ sources: [...this.sources] });\n };\n\n activate = () => {\n if (!this.activeSources.length) {\n const sourcesToActivate = this.config.keepSingleActiveSource\n ? this.sources.slice(0, 1)\n : this.sources;\n sourcesToActivate.forEach((s) => s.activate());\n }\n if (this.isActive) return;\n this.state.partialNext({ isActive: true });\n };\n\n search = async (searchQuery?: string) => {\n const searchedSources = this.activeSources;\n this.state.partialNext({\n searchQuery,\n });\n await Promise.all(searchedSources.map((source) => source.search(searchQuery)));\n };\n\n cancelSearchQueries = () => {\n this.activeSources.forEach((s) => s.cancelScheduledQuery());\n };\n\n clear = () => {\n this.cancelSearchQueries();\n this.sources.forEach((source) =>\n source.state.next({ ...source.initialState, isActive: source.isActive }),\n );\n this.state.next((current) => ({\n ...current,\n isActive: true,\n queriesInProgress: [],\n searchQuery: '',\n }));\n };\n\n exit = () => {\n this.cancelSearchQueries();\n this.sources.forEach((source) =>\n source.state.next({ ...source.initialState, isActive: source.isActive }),\n );\n this.state.next((current) => ({\n ...current,\n isActive: false,\n queriesInProgress: [],\n searchQuery: '',\n }));\n };\n}\n", "import { StateStore } from '../store';\nimport { debounce, type DebouncedFunc } from '../utils';\n\ntype PaginationDirection = 'next' | 'prev';\ntype Cursor = { next: string | null; prev: string | null };\nexport type PaginationQueryParams = { direction: PaginationDirection };\nexport type PaginationQueryReturnValue<T> = { items: T[] } & {\n next?: string;\n prev?: string;\n};\nexport type PaginatorDebounceOptions = {\n debounceMs: number;\n};\ntype DebouncedExecQueryFunction = DebouncedFunc<\n (params: { direction: PaginationDirection }) => Promise<void>\n>;\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport type PaginatorState<T = any> = {\n hasNext: boolean;\n hasPrev: boolean;\n isLoading: boolean;\n items: T[] | undefined;\n lastQueryError?: Error;\n cursor?: Cursor;\n offset?: number;\n};\n\nexport type PaginatorOptions = {\n /** The number of milliseconds to debounce the search query. The default interval is 300ms. */\n debounceMs?: number;\n pageSize?: number;\n};\nexport const DEFAULT_PAGINATION_OPTIONS: Required<PaginatorOptions> = {\n debounceMs: 300,\n pageSize: 10,\n} as const;\n\nexport abstract class BasePaginator<T> {\n state: StateStore<PaginatorState<T>>;\n pageSize: number;\n protected _executeQueryDebounced!: DebouncedExecQueryFunction;\n protected _isCursorPagination = false;\n\n protected constructor(options?: PaginatorOptions) {\n const { debounceMs, pageSize } = { ...DEFAULT_PAGINATION_OPTIONS, ...options };\n this.pageSize = pageSize;\n this.state = new StateStore<PaginatorState<T>>(this.initialState);\n this.setDebounceOptions({ debounceMs });\n }\n\n get lastQueryError() {\n return this.state.getLatestValue().lastQueryError;\n }\n\n get hasNext() {\n return this.state.getLatestValue().hasNext;\n }\n\n get hasPrev() {\n return this.state.getLatestValue().hasPrev;\n }\n\n get hasResults() {\n return Array.isArray(this.state.getLatestValue().items);\n }\n\n get isLoading() {\n return this.state.getLatestValue().isLoading;\n }\n\n get initialState(): PaginatorState {\n return {\n hasNext: true,\n hasPrev: true, //todo: check if optimistic value does not cause problems in UI\n isLoading: false,\n items: undefined,\n lastQueryError: undefined,\n cursor: undefined,\n offset: 0,\n };\n }\n\n get items() {\n return this.state.getLatestValue().items;\n }\n\n get cursor() {\n return this.state.getLatestValue().cursor;\n }\n\n get offset() {\n return this.state.getLatestValue().offset;\n }\n\n abstract query(params: PaginationQueryParams): Promise<PaginationQueryReturnValue<T>>;\n\n abstract filterQueryResults(items: T[]): T[] | Promise<T[]>;\n\n setDebounceOptions = ({ debounceMs }: PaginatorDebounceOptions) => {\n this._executeQueryDebounced = debounce(this.executeQuery.bind(this), debounceMs);\n };\n\n canExecuteQuery = (direction: PaginationDirection) =>\n (!this.isLoading && direction === 'next' && this.hasNext) ||\n (direction === 'prev' && this.hasPrev);\n\n protected getStateBeforeFirstQuery(): PaginatorState<T> {\n return {\n ...this.initialState,\n isLoading: true,\n };\n }\n\n protected getStateAfterQuery(\n stateUpdate: Partial<PaginatorState<T>>,\n isFirstPage: boolean,\n ): PaginatorState<T> {\n const current = this.state.getLatestValue();\n return {\n ...current,\n lastQueryError: undefined, // reset lastQueryError that can be overridden by the stateUpdate\n ...stateUpdate,\n isLoading: false,\n items: isFirstPage\n ? stateUpdate.items\n : [...(this.items ?? []), ...(stateUpdate.items || [])],\n };\n }\n\n async executeQuery({ direction }: { direction: PaginationDirection }) {\n if (!this.canExecuteQuery(direction)) return;\n const isFirstPage = typeof this.items === 'undefined';\n if (isFirstPage) {\n this.state.next(this.getStateBeforeFirstQuery());\n } else {\n this.state.partialNext({ isLoading: true });\n }\n\n const stateUpdate: Partial<PaginatorState<T>> = {};\n try {\n const results = await this.query({ direction });\n if (!results) return;\n const { items, next, prev } = results;\n if (isFirstPage && (next || prev)) {\n this._isCursorPagination = true;\n }\n\n if (this._isCursorPagination) {\n stateUpdate.cursor = { next: next || null, prev: prev || null };\n stateUpdate.hasNext = !!next;\n stateUpdate.hasPrev = !!prev;\n } else {\n stateUpdate.offset = (this.offset ?? 0) + items.length;\n stateUpdate.hasNext = items.length === this.pageSize;\n }\n\n stateUpdate.items = await this.filterQueryResults(items);\n } catch (e) {\n stateUpdate.lastQueryError = e as Error;\n } finally {\n this.state.next(this.getStateAfterQuery(stateUpdate, isFirstPage));\n }\n }\n\n cancelScheduledQuery() {\n this._executeQueryDebounced.cancel();\n }\n\n resetState() {\n this.state.next(this.initialState);\n }\n\n next = () => this.executeQuery({ direction: 'next' });\n\n prev = () => this.executeQuery({ direction: 'prev' });\n\n nextDebounced = () => {\n this._executeQueryDebounced({ direction: 'next' });\n };\n prevDebounced = () => {\n this._executeQueryDebounced({ direction: 'prev' });\n };\n}\n", "import { StateStore } from '../store';\nimport type { ArrayOneOrMore, ArrayTwoOrMore, QueryFilter } from '../types';\n\ntype ElementType<T> = T extends (infer U)[] ? U : T;\n\n// redeclared because QueryFilter does not account for the additional operators\nexport type ExtendedQueryFilter<T = string> = QueryFilter<T> & {\n $autocomplete?: T extends string ? string : never;\n $contains?: ElementType<T>;\n $in?: ElementType<T>[];\n $q?: T extends string ? string : never;\n};\n\nexport type ExtendedQueryLogicalOperators<T> = {\n $and?: ArrayOneOrMore<ExtendedQueryFilters<T>>;\n $nor?: ArrayOneOrMore<ExtendedQueryFilters<T>>;\n $or?: ArrayTwoOrMore<ExtendedQueryFilters<T>>;\n};\n\nexport type ExtendedQueryFilters<T> = {\n [K in keyof T]?: ExtendedQueryFilter<T[K]>;\n} & ExtendedQueryLogicalOperators<T>;\n\nexport type FilterBuilderGenerators<\n TFilters,\n TContext extends Record<string, unknown> = {},\n> = {\n [K in string]: {\n enabled: boolean;\n generate: (context: TContext) => Partial<TFilters> | null;\n };\n};\n\nexport type FilterBuilderOptions<TFilters, TContext extends Record<string, unknown>> = {\n initialFilterConfig?: FilterBuilderGenerators<TFilters, TContext>;\n initialContext?: TContext;\n};\n\nexport class FilterBuilder<TFilters, TContext extends Record<string, unknown> = {}> {\n filterConfig: StateStore<FilterBuilderGenerators<TFilters, TContext>>;\n context: StateStore<TContext>;\n\n constructor(params?: FilterBuilderOptions<TFilters, TContext>) {\n this.context = new StateStore(params?.initialContext ?? ({} as TContext));\n this.filterConfig = new StateStore(\n params?.initialFilterConfig ?? ({} as FilterBuilderGenerators<TFilters, TContext>),\n );\n }\n\n updateFilterConfig(config: Partial<FilterBuilderGenerators<TFilters, TContext>>) {\n this.filterConfig.partialNext(config);\n }\n\n enableFilter(filterKey: keyof FilterBuilderGenerators<TFilters, TContext>) {\n const config = this.filterConfig.getLatestValue();\n if (config[filterKey]) {\n this.filterConfig.partialNext({\n [filterKey]: {\n ...config[filterKey],\n enabled: true,\n },\n });\n }\n }\n\n disableFilter(filterKey: keyof FilterBuilderGenerators<TFilters, TContext>) {\n const config = this.filterConfig.getLatestValue();\n if (config[filterKey]) {\n this.filterConfig.partialNext({\n [filterKey]: {\n ...config[filterKey],\n enabled: false,\n },\n });\n }\n }\n\n updateContext(newContext: Partial<TContext>) {\n this.context.partialNext(newContext);\n }\n\n buildFilters(params?: {\n context?: Partial<TContext>;\n baseFilters?: Partial<TFilters>;\n }): Partial<TFilters> {\n const filters: Partial<TFilters> = {\n ...(params?.baseFilters ?? {}),\n } as Partial<TFilters>;\n\n const filterConfig = this.filterConfig.getLatestValue();\n for (const key in filterConfig) {\n const configItem = filterConfig[key];\n if (!configItem?.enabled) continue;\n\n const generated = configItem.generate({\n ...this.context.getLatestValue(),\n ...(params?.context ?? {}),\n });\n if (generated) Object.assign(filters, generated);\n }\n\n return filters;\n }\n}\n", "import { BasePaginator } from './BasePaginator';\nimport type {\n PaginationQueryParams,\n PaginationQueryReturnValue,\n PaginatorOptions,\n} from './BasePaginator';\nimport type { ReminderFilters, ReminderResponse, ReminderSort } from '../types';\nimport type { StreamChat } from '../client';\n\nexport class ReminderPaginator extends BasePaginator<ReminderResponse> {\n private client: StreamChat;\n protected _filters: ReminderFilters | undefined;\n protected _sort: ReminderSort | undefined;\n\n get filters(): ReminderFilters | undefined {\n return this._filters;\n }\n\n get sort(): ReminderSort | undefined {\n return this._sort;\n }\n\n set filters(filters: ReminderFilters | undefined) {\n this._filters = filters;\n this.resetState();\n }\n\n set sort(sort: ReminderSort | undefined) {\n this._sort = sort;\n this.resetState();\n }\n\n constructor(client: StreamChat, options?: PaginatorOptions) {\n super(options);\n this.client = client;\n }\n\n query = async ({\n direction,\n }: PaginationQueryParams): Promise<PaginationQueryReturnValue<ReminderResponse>> => {\n const cursor = this.cursor?.[direction];\n const {\n reminders: items,\n next,\n prev,\n } = await this.client.queryReminders({\n filter: this.filters,\n sort: this.sort,\n limit: this.pageSize,\n [direction]: cursor,\n });\n return { items, next, prev };\n };\n\n filterQueryResults = (items: ReminderResponse[]) => items;\n}\n", "import { BaseSearchSource } from './BaseSearchSource';\nimport { FilterBuilder, type FilterBuilderOptions } from '../pagination';\nimport type { StreamChat } from '../client';\nimport type { UserFilters, UserOptions, UserResponse, UserSort } from '../types';\nimport type { SearchSourceOptions } from './types';\n\ntype CustomContext = Record<string, unknown>;\n\nexport type UserSearchSourceFilterBuilderContext<\n C extends CustomContext = CustomContext,\n> = { searchQuery?: string } & C;\n\nexport class UserSearchSource<\n TFilterContext extends CustomContext = CustomContext,\n> extends BaseSearchSource<UserResponse> {\n readonly type = 'users';\n client: StreamChat;\n filters: UserFilters | undefined;\n sort: UserSort | undefined;\n searchOptions: Omit<UserOptions, 'limit' | 'offset'> | undefined;\n filterBuilder: FilterBuilder<\n UserFilters,\n UserSearchSourceFilterBuilderContext<TFilterContext>\n >;\n\n constructor(\n client: StreamChat,\n options?: SearchSourceOptions,\n filterBuilderOptions: FilterBuilderOptions<\n UserFilters,\n UserSearchSourceFilterBuilderContext<TFilterContext>\n > = {},\n ) {\n super(options);\n this.client = client;\n this.filterBuilder = new FilterBuilder<\n UserFilters,\n UserSearchSourceFilterBuilderContext<TFilterContext>\n >({\n initialFilterConfig: {\n $or: {\n enabled: true,\n generate: ({ searchQuery }) =>\n searchQuery\n ? {\n $or: [\n { id: { $autocomplete: searchQuery } },\n { name: { $autocomplete: searchQuery } },\n ],\n }\n : null,\n },\n },\n ...filterBuilderOptions,\n });\n }\n\n protected async query(searchQuery: string) {\n const filters = this.filterBuilder.buildFilters({\n baseFilters: this.filters,\n context: { searchQuery } as UserSearchSourceFilterBuilderContext<TFilterContext>,\n });\n const sort = { id: 1, ...this.sort } as UserSort;\n const options = { ...this.searchOptions, limit: this.pageSize, offset: this.offset };\n const { users } = await this.client.queryUsers(filters, sort, options);\n return { items: users };\n }\n\n protected filterQueryResults(items: UserResponse[]) {\n return items.filter((u) => u.id !== this.client.user?.id);\n }\n}\n", "import { BaseSearchSource } from './BaseSearchSource';\nimport type { FilterBuilderOptions } from '../pagination';\nimport { FilterBuilder } from '../pagination';\nimport type { Channel } from '../channel';\nimport type { StreamChat } from '../client';\nimport type { ChannelFilters, ChannelOptions, ChannelSort } from '../types';\nimport type { SearchSourceOptions } from './types';\n\ntype CustomContext = Record<string, unknown>;\n\nexport type ChannelSearchSourceFilterBuilderContext<\n C extends CustomContext = CustomContext,\n> = { searchQuery?: string } & C;\n\nexport class ChannelSearchSource<\n TFilterContext extends CustomContext = CustomContext,\n> extends BaseSearchSource<Channel> {\n readonly type = 'channels';\n client: StreamChat;\n filters: ChannelFilters | undefined;\n sort: ChannelSort | undefined;\n searchOptions: Omit<ChannelOptions, 'limit' | 'offset'> | undefined;\n filterBuilder: FilterBuilder<\n ChannelFilters,\n ChannelSearchSourceFilterBuilderContext<TFilterContext>\n >;\n\n constructor(\n client: StreamChat,\n options?: SearchSourceOptions,\n filterBuilderOptions: FilterBuilderOptions<\n ChannelFilters,\n ChannelSearchSourceFilterBuilderContext<TFilterContext>\n > = {},\n ) {\n super(options);\n this.client = client;\n this.filterBuilder = new FilterBuilder<\n ChannelFilters,\n ChannelSearchSourceFilterBuilderContext<TFilterContext>\n >({\n ...filterBuilderOptions,\n initialFilterConfig: {\n name: {\n enabled: true,\n generate: ({ searchQuery }) =>\n searchQuery ? { name: { $autocomplete: searchQuery } } : null,\n },\n ...filterBuilderOptions.initialFilterConfig,\n },\n });\n }\n\n protected async query(searchQuery: string) {\n const filters = this.filterBuilder.buildFilters({\n baseFilters: {\n ...(this.client.userID ? { members: { $in: [this.client.userID] } } : {}),\n ...this.filters,\n },\n context: { searchQuery } as Partial<\n ChannelSearchSourceFilterBuilderContext<TFilterContext>\n >,\n });\n const sort = this.sort ?? {};\n const options = { ...this.searchOptions, limit: this.pageSize, offset: this.offset };\n const items = await this.client.queryChannels(filters, sort, options);\n return { items };\n }\n\n protected filterQueryResults(items: Channel[]) {\n return items;\n }\n}\n", "import { BaseSearchSource } from './BaseSearchSource';\nimport type {\n ChannelFilters,\n ChannelOptions,\n ChannelSort,\n MessageFilters,\n MessageResponse,\n SearchMessageSort,\n SearchOptions,\n} from '../types';\nimport type { StreamChat } from '../client';\nimport type { SearchSourceOptions } from './types';\nimport { FilterBuilder, type FilterBuilderOptions } from '../pagination';\n\ntype CustomContext = Record<string, unknown>;\n\n// Built-in contexts per builder\ntype BuiltInContexts = {\n messageSearchChannel: { searchQuery?: string };\n messageSearch: { searchQuery?: string };\n channelQuery: { cids?: string[] };\n};\n\n// Merge Built-in with user-provided Custom context\ntype MergeContext<\n B extends Record<string, unknown>,\n C extends CustomContext | undefined,\n> = B & (C extends object ? C : {});\n\n// User can provide custom context for each builder\ntype MessageSearchSourceContexts = Partial<{\n messageSearchChannelContext: Record<string, unknown>;\n messageSearchContext: Record<string, unknown>;\n channelQueryContext: Record<string, unknown>;\n}>;\n\nexport type MessageSearchSourceFilterBuilderOptions<\n TContexts extends MessageSearchSourceContexts = {},\n> = Partial<{\n messageSearchChannel: FilterBuilderOptions<\n ChannelFilters,\n MergeContext<\n BuiltInContexts['messageSearchChannel'],\n TContexts['messageSearchChannelContext']\n >\n >;\n messageSearch: FilterBuilderOptions<\n MessageFilters,\n MergeContext<BuiltInContexts['messageSearch'], TContexts['messageSearchContext']>\n >;\n channelQuery: FilterBuilderOptions<\n ChannelFilters,\n MergeContext<BuiltInContexts['channelQuery'], TContexts['channelQueryContext']>\n >;\n}>;\n\nexport class MessageSearchSource<\n TContexts extends MessageSearchSourceContexts = {},\n> extends BaseSearchSource<MessageResponse> {\n readonly type = 'messages';\n private client: StreamChat;\n\n messageSearchChannelFilters: ChannelFilters | undefined;\n messageSearchFilters: MessageFilters | undefined;\n messageSearchSort: SearchMessageSort | undefined;\n\n channelQueryFilters: ChannelFilters | undefined;\n channelQuerySort: ChannelSort | undefined;\n channelQueryOptions: Omit<ChannelOptions, 'limit' | 'offset'> | undefined;\n\n messageSearchChannelFilterBuilder: FilterBuilder<\n ChannelFilters,\n MergeContext<\n BuiltInContexts['messageSearchChannel'],\n TContexts['messageSearchChannelContext']\n >\n >;\n messageSearchFilterBuilder: FilterBuilder<\n MessageFilters,\n MergeContext<BuiltInContexts['messageSearch'], TContexts['messageSearchContext']>\n >;\n channelQueryFilterBuilder: FilterBuilder<\n ChannelFilters,\n MergeContext<BuiltInContexts['channelQuery'], TContexts['channelQueryContext']>\n >;\n\n constructor(\n client: StreamChat,\n options?: SearchSourceOptions,\n filterBuilderOptions?: MessageSearchSourceFilterBuilderOptions<TContexts>,\n ) {\n super(options);\n this.client = client;\n\n this.messageSearchChannelFilterBuilder = new FilterBuilder<\n ChannelFilters,\n MergeContext<\n BuiltInContexts['messageSearchChannel'],\n TContexts['messageSearchChannelContext']\n >\n >(filterBuilderOptions?.messageSearchChannel);\n\n this.messageSearchFilterBuilder = new FilterBuilder<\n MessageFilters,\n MergeContext<BuiltInContexts['messageSearch'], TContexts['messageSearchContext']>\n >({\n ...filterBuilderOptions?.messageSearch,\n initialFilterConfig: {\n text: {\n enabled: true,\n generate: ({ searchQuery }) => (searchQuery ? { text: searchQuery } : null),\n },\n ...filterBuilderOptions?.messageSearch?.initialFilterConfig,\n },\n });\n\n this.channelQueryFilterBuilder = new FilterBuilder<\n ChannelFilters,\n MergeContext<BuiltInContexts['channelQuery'], TContexts['channelQueryContext']>\n >({\n ...filterBuilderOptions?.channelQuery,\n initialFilterConfig: {\n cid: {\n enabled: true,\n generate: ({ cids }) => (cids ? { cid: { $in: cids } } : null),\n },\n ...filterBuilderOptions?.channelQuery?.initialFilterConfig,\n },\n });\n }\n\n protected async query(searchQuery: string) {\n if (!this.client.userID || !searchQuery || this.next === null) return { items: [] };\n\n const channelFilters = this.messageSearchChannelFilterBuilder.buildFilters({\n baseFilters: {\n ...(this.client.userID ? { members: { $in: [this.client.userID] } } : {}),\n ...this.messageSearchChannelFilters,\n },\n context: { searchQuery } as Partial<\n MergeContext<\n BuiltInContexts['messageSearchChannel'],\n TContexts['messageSearchChannelContext']\n >\n >,\n });\n\n const messageFilters: MessageFilters = this.messageSearchFilterBuilder.buildFilters({\n baseFilters: {\n type: 'regular',\n ...this.messageSearchFilters,\n },\n context: { searchQuery } as Partial<\n MergeContext<BuiltInContexts['messageSearch'], TContexts['messageSearchContext']>\n >,\n });\n\n const sort: SearchMessageSort = {\n created_at: -1,\n ...this.messageSearchSort,\n };\n\n const options: SearchOptions = {\n limit: this.pageSize,\n next: this.next,\n sort,\n };\n\n const { next, results } = await this.client.search(\n channelFilters,\n messageFilters,\n options,\n );\n const items = results.map(({ message }) => message);\n\n const cids = Array.from(\n items.reduce((acc, message) => {\n if (message.cid && !this.client.activeChannels[message.cid]) acc.add(message.cid);\n return acc;\n }, new Set<string>()),\n );\n\n if (cids.length > 0) {\n const channelQueryFilters = this.channelQueryFilterBuilder.buildFilters({\n baseFilters: this.channelQueryFilters,\n context: { cids } as Partial<\n MergeContext<BuiltInContexts['channelQuery'], TContexts['channelQueryContext']>\n >,\n });\n await this.client.queryChannels(\n channelQueryFilters,\n {\n last_message_at: -1,\n ...this.channelQuerySort,\n },\n this.channelQueryOptions,\n );\n }\n\n return { items, next };\n }\n\n protected filterQueryResults(items: MessageResponse[]) {\n return items;\n }\n}\n", "import type { TextSelection } from './types';\n\n/**\n * For commands, we want to match all patterns except:\n * 1. Text not starting with trigger\n * 2. Trigger in middle of text\n */\nexport const getTriggerCharWithToken = ({\n trigger,\n text,\n isCommand = false,\n acceptTrailingSpaces = true,\n}: {\n trigger: string;\n text: string;\n isCommand?: boolean;\n acceptTrailingSpaces?: boolean;\n}) => {\n const triggerNorWhitespace = `[^\\\\s${trigger}]*`;\n\n const match = text.match(\n new RegExp(\n isCommand\n ? `^[${trigger}]${triggerNorWhitespace}$`\n : acceptTrailingSpaces\n ? `(?!^|\\\\W)?[${trigger}]${triggerNorWhitespace}\\\\s?${triggerNorWhitespace}$`\n : `(?!^|\\\\W)?[${trigger}]${triggerNorWhitespace}$`,\n 'g',\n ),\n );\n\n return match && match[match.length - 1].trim();\n};\n\nexport const getCompleteCommandInString = (text: string) => {\n // starts with \"/\" followed by 1+ non-whitespace chars followed by 1+ white-space chars\n // the comand name is extracted into a separate group\n const match = text.match(/^\\/(\\S+)\\s+.*/);\n const commandName = match && match[1];\n return commandName;\n};\n\nexport const insertItemWithTrigger = ({\n insertText,\n selection,\n text,\n trigger,\n}: {\n insertText: string;\n selection: TextSelection;\n text: string;\n trigger: string;\n}) => {\n const beforeCursor = text.slice(0, selection.end);\n const afterCursor = text.slice(selection.end);\n\n // Replace the trigger and query with the user mention\n const lastIndex = beforeCursor.lastIndexOf(trigger);\n const newText = beforeCursor.slice(0, lastIndex) + insertText + afterCursor;\n return {\n text: newText,\n selection: {\n start: lastIndex + insertText.length,\n end: lastIndex + insertText.length,\n },\n };\n};\n\nexport const replaceWordWithEntity = async ({\n caretPosition,\n getEntityString,\n text,\n}: {\n caretPosition: number;\n getEntityString: (word: string) => Promise<string | null> | string | null;\n text: string;\n}): Promise<string> => {\n const lastWordRegex = /([^\\s]+)(\\s*)$/;\n const match = lastWordRegex.exec(text.slice(0, caretPosition));\n if (!match) return text;\n\n const lastWord = match[1];\n if (!lastWord) return text;\n\n const spaces = match[2];\n\n const newWord = await getEntityString(lastWord);\n if (newWord == null) return text;\n\n const textBeforeWord = text.slice(0, caretPosition - match[0].length);\n const textAfterCaret = text.slice(caretPosition, -1);\n return textBeforeWord + newWord + spaces + textAfterCaret;\n};\n\n/**\n * Escapes a string for use in a regular expression\n * @param text - The string to escape\n * @returns The escaped string\n * What does this regex do?\n\n The regex escapes special regex characters by adding a backslash before them. Here's what it matches:\n - dash\n [ ] square brackets\n { } curly braces\n ( ) parentheses\n * asterisk\n + plus\n ? question mark\n . period\n , comma\n / forward slash\n \\ backslash\n ^ caret\n $ dollar sign\n | pipe\n # hash\n\n The \\\\$& replacement adds a backslash before any matched character.\n This is needed when you want to use these characters literally\n in a regex pattern instead of their special regex meanings.\n For example:\n escapeRegExp(\"hello.world\") // Returns: \"hello\\.world\"\n escapeRegExp(\"[test]\") // Returns: \"\\[test\\]\"\n\n This is commonly used when building dynamic regex patterns from user input to prevent special characters from being interpreted as regex syntax.\n */\nexport function escapeRegExp(text: string) {\n return text.replace(/[-[\\]{}()*+?.,/\\\\^$|#]/g, '\\\\$&');\n}\n\nexport type TokenizationPayload = {\n tokenizedDisplayName: { token: string; parts: string[] };\n};\n\nexport const getTokenizedSuggestionDisplayName = ({\n displayName,\n searchToken,\n}: {\n displayName: string;\n searchToken: string;\n}): TokenizationPayload => ({\n tokenizedDisplayName: {\n token: searchToken,\n parts: searchToken\n ? displayName\n .split(new RegExp(`(${escapeRegExp(searchToken)})`, 'gi'))\n .filter(Boolean)\n : [displayName],\n },\n});\n", "import type { Channel } from '../../../channel';\nimport type { Middleware } from '../../../middleware';\nimport type { SearchSourceOptions } from '../../../search';\nimport { BaseSearchSourceSync } from '../../../search';\nimport type { CommandResponse } from '../../../types';\nimport { mergeWith } from '../../../utils/mergeWith';\nimport type { CommandSuggestion, TextComposerMiddlewareOptions } from './types';\nimport {\n getCompleteCommandInString,\n getTriggerCharWithToken,\n insertItemWithTrigger,\n} from './textMiddlewareUtils';\nimport type { TextComposerMiddlewareExecutorState } from './TextComposerMiddlewareExecutor';\n\nexport class CommandSearchSource extends BaseSearchSourceSync<CommandSuggestion> {\n readonly type = 'commands';\n private channel: Channel;\n\n constructor(channel: Channel, options?: SearchSourceOptions) {\n super(options);\n this.channel = channel;\n }\n\n canExecuteQuery = (newSearchString?: string) => {\n const hasNewSearchQuery = typeof newSearchString !== 'undefined';\n return this.isActive && !this.isLoading && (this.hasNext || hasNewSearchQuery);\n };\n\n getStateBeforeFirstQuery(newSearchString: string) {\n const newState = super.getStateBeforeFirstQuery(newSearchString);\n const { items } = this.state.getLatestValue();\n return {\n ...newState,\n items, // preserve items to avoid flickering\n };\n }\n\n query(searchQuery: string) {\n const channelConfig = this.channel.getConfig();\n const commands = channelConfig?.commands || [];\n const selectedCommands: (CommandResponse & { name: string })[] = commands.filter(\n (command): command is CommandResponse & { name: string } =>\n !!(\n command.name &&\n command.name.toLowerCase().indexOf(searchQuery.toLowerCase()) !== -1\n ),\n );\n\n // sort alphabetically unless you're matching the first char\n selectedCommands.sort((a, b) => {\n let nameA = a.name?.toLowerCase();\n let nameB = b.name?.toLowerCase();\n if (nameA?.indexOf(searchQuery) === 0) {\n nameA = `0${nameA}`;\n }\n if (nameB?.indexOf(searchQuery) === 0) {\n nameB = `0${nameB}`;\n }\n // Should confirm possible null / undefined when TS is fully implemented\n if (nameA != null && nameB != null) {\n if (nameA < nameB) {\n return -1;\n }\n if (nameA > nameB) {\n return 1;\n }\n }\n\n return 0;\n });\n\n return {\n items: selectedCommands.map((c) => ({ ...c, id: c.name })),\n next: null,\n };\n }\n\n protected filterQueryResults(items: CommandSuggestion[]) {\n return items;\n }\n}\n\n/**\n * TextComposer middleware for mentions\n * Usage:\n *\n * const textComposer = new TextComposer(options);\n *\n * textComposer.use(createCommandsMiddleware(channel, { trigger: '//', minChars: 2 } ));\n *\n * @param channel\n * @param {{ minChars: number; trigger: string }} options\n * @returns\n */\n\nconst DEFAULT_OPTIONS: TextComposerMiddlewareOptions = { minChars: 1, trigger: '/' };\n\nexport type CommandsMiddleware = Middleware<\n TextComposerMiddlewareExecutorState<CommandSuggestion>,\n 'onChange' | 'onSuggestionItemSelect'\n>;\n\nexport const createCommandsMiddleware = (\n channel: Channel,\n options?: Partial<TextComposerMiddlewareOptions> & {\n searchSource?: CommandSearchSource;\n },\n): CommandsMiddleware => {\n const finalOptions = mergeWith(DEFAULT_OPTIONS, options ?? {});\n let searchSource = new CommandSearchSource(channel);\n if (options?.searchSource) {\n searchSource = options.searchSource;\n searchSource.resetState();\n }\n searchSource.activate();\n\n return {\n id: 'stream-io/text-composer/commands-middleware',\n handlers: {\n onChange: ({ state, next, complete, forward }) => {\n if (!state.selection) return forward();\n const finalText = state.text.slice(0, state.selection.end);\n const commandName = getCompleteCommandInString(finalText);\n if (commandName) {\n const command = searchSource?.query(commandName).items[0];\n if (command) {\n return next({\n ...state,\n command,\n suggestions: undefined,\n });\n }\n }\n\n const triggerWithToken = getTriggerCharWithToken({\n trigger: finalOptions.trigger,\n text: finalText,\n acceptTrailingSpaces: false,\n isCommand: true,\n });\n\n const newSearchTriggerred =\n triggerWithToken && triggerWithToken.length === finalOptions.minChars;\n\n if (newSearchTriggerred) {\n searchSource.resetStateAndActivate();\n }\n\n const triggerWasRemoved =\n !triggerWithToken || triggerWithToken.length < finalOptions.minChars;\n\n if (triggerWasRemoved) {\n const hasStaleSuggestions = state.suggestions?.trigger === finalOptions.trigger;\n const newState = { ...state };\n if (hasStaleSuggestions) {\n delete newState.suggestions;\n }\n return next(newState);\n }\n\n return complete({\n ...state,\n command: null,\n suggestions: {\n query: triggerWithToken.slice(1),\n searchSource,\n trigger: finalOptions.trigger,\n },\n });\n },\n onSuggestionItemSelect: ({ state, next, forward }) => {\n const { selectedSuggestion } = state.change ?? {};\n if (!selectedSuggestion || state.suggestions?.trigger !== finalOptions.trigger)\n return forward();\n\n searchSource.resetStateAndActivate();\n return next({\n ...state,\n ...insertItemWithTrigger({\n insertText: `/${selectedSuggestion.name} `,\n selection: state.selection,\n text: state.text,\n trigger: finalOptions.trigger,\n }),\n command: selectedSuggestion,\n suggestions: undefined,\n });\n },\n },\n };\n};\n", "import type { TextComposerMiddlewareExecutorState } from './TextComposerMiddlewareExecutor';\nimport type { CommandSuggestion } from './types';\nimport type { Middleware } from '../../../middleware';\nimport { escapeRegExp } from './textMiddlewareUtils';\n\nexport type CommandStringExtractionMiddleware = Middleware<\n TextComposerMiddlewareExecutorState<CommandSuggestion>,\n 'onChange' | 'onSuggestionItemSelect'\n>;\n\nconst stripCommandFromText = (text: string, commandName: string) =>\n text.replace(new RegExp(`^${escapeRegExp(`/${commandName}`)}\\\\s*`), '');\n\nexport const createCommandStringExtractionMiddleware =\n (): CommandStringExtractionMiddleware => ({\n handlers: {\n onChange: ({ complete, forward, state }) => {\n const { command } = state;\n\n if (!command?.name) {\n return forward();\n }\n\n const newText = stripCommandFromText(state.text, command.name);\n\n return complete({\n ...state,\n selection: {\n end: newText.length,\n start: newText.length,\n },\n text: newText,\n });\n },\n onSuggestionItemSelect: ({ next, forward, state }) => {\n const { command } = state;\n\n if (!command) {\n return forward();\n }\n\n const triggerWithCommand = `/${command?.name} `;\n\n const newText = state.text.slice(triggerWithCommand.length);\n return next({\n ...state,\n selection: {\n end: newText.length,\n start: newText.length,\n },\n text: newText,\n });\n },\n },\n id: 'stream-io/text-composer/command-string-extraction',\n });\n", "import {\n getTokenizedSuggestionDisplayName,\n getTriggerCharWithToken,\n insertItemWithTrigger,\n} from './textMiddlewareUtils';\nimport { BaseSearchSource, type SearchSourceOptions } from '../../../search';\nimport { mergeWith } from '../../../utils/mergeWith';\nimport type { TextComposerMiddlewareOptions, UserSuggestion } from './types';\nimport type { StreamChat } from '../../../client';\nimport type {\n MemberFilters,\n MemberSort,\n UserFilters,\n UserOptions,\n UserResponse,\n UserSort,\n} from '../../../types';\nimport type { Channel } from '../../../channel';\nimport { MAX_CHANNEL_MEMBER_COUNT_IN_CHANNEL_QUERY } from '../../../constants';\nimport type { Middleware } from '../../../middleware';\nimport type { TextComposerMiddlewareExecutorState } from './TextComposerMiddlewareExecutor';\n\n// todo: the map is too small - Slavic letters with diacritics are missing for example\nexport const accentsMap: { [key: string]: string } = {\n a: '\u00E1|\u00E0|\u00E3|\u00E2|\u00C0|\u00C1|\u00C3|\u00C2',\n c: '\u00E7|\u00C7',\n e: '\u00E9|\u00E8|\u00EA|\u00C9|\u00C8|\u00CA',\n i: '\u00ED|\u00EC|\u00EE|\u00CD|\u00CC|\u00CE',\n n: '\u00F1|\u00D1',\n o: '\u00F3|\u00F2|\u00F4|\u0151|\u00F5|\u00D3|\u00D2|\u00D4|\u00D5',\n u: '\u00FA|\u00F9|\u00FB|\u00FC|\u00DA|\u00D9|\u00DB|\u00DC',\n};\n\nexport const removeDiacritics = (text?: string) => {\n if (!text) return '';\n return Object.keys(accentsMap).reduce(\n (acc, current) => acc.replace(new RegExp(accentsMap[current], 'g'), current),\n text,\n );\n};\n\nexport const calculateLevenshtein = (query: string, name: string) => {\n if (query.length === 0) return name.length;\n if (name.length === 0) return query.length;\n\n const matrix = [];\n\n let i;\n for (i = 0; i <= name.length; i++) {\n matrix[i] = [i];\n }\n\n let j;\n for (j = 0; j <= query.length; j++) {\n matrix[0][j] = j;\n }\n\n for (i = 1; i <= name.length; i++) {\n for (j = 1; j <= query.length; j++) {\n if (name.charAt(i - 1) === query.charAt(j - 1)) {\n matrix[i][j] = matrix[i - 1][j - 1];\n } else {\n matrix[i][j] = Math.min(\n matrix[i - 1][j - 1] + 1, // substitution\n Math.min(\n matrix[i][j - 1] + 1, // insertion\n matrix[i - 1][j] + 1,\n ),\n ); // deletion\n }\n }\n }\n\n return matrix[name.length][query.length];\n};\n\nexport type MentionsSearchSourceOptions = SearchSourceOptions & {\n mentionAllAppUsers?: boolean;\n textComposerText?: string;\n // todo: document that if you want transliteration, you need to provide the function, e.g. import {default: transliterate} from '@sindresorhus/transliterate';\n // this is now replacing a parameter useMentionsTransliteration\n transliterate?: (text: string) => string;\n};\n\nexport class MentionsSearchSource extends BaseSearchSource<UserSuggestion> {\n readonly type = 'mentions';\n private client: StreamChat;\n private channel: Channel;\n userFilters: UserFilters | undefined;\n memberFilters: MemberFilters | undefined;\n userSort: UserSort | undefined;\n memberSort: MemberSort | undefined; // todo: document there are filters and sort options for users and members\n searchOptions: Omit<UserOptions, 'limit' | 'offset'> | undefined;\n config: MentionsSearchSourceOptions;\n\n constructor(channel: Channel, options?: MentionsSearchSourceOptions) {\n const { mentionAllAppUsers, textComposerText, transliterate, ...restOptions } =\n options || {};\n super(restOptions);\n this.client = channel.getClient();\n this.channel = channel;\n this.config = { mentionAllAppUsers, textComposerText };\n\n if (transliterate) {\n this.transliterate = transliterate;\n }\n }\n\n get allMembersLoadedWithInitialChannelQuery() {\n const countLoadedMembers = Object.keys(this.channel.state.members || {}).length;\n return countLoadedMembers < MAX_CHANNEL_MEMBER_COUNT_IN_CHANNEL_QUERY;\n }\n\n getStateBeforeFirstQuery(newSearchString: string) {\n const newState = super.getStateBeforeFirstQuery(newSearchString);\n const { items } = this.state.getLatestValue();\n return {\n ...newState,\n items, // preserve items to avoid flickering\n };\n }\n\n canExecuteQuery = (newSearchString?: string) => {\n const hasNewSearchQuery = typeof newSearchString !== 'undefined';\n return this.isActive && !this.isLoading && (hasNewSearchQuery || this.hasNext);\n };\n\n transliterate = (text: string) => text;\n\n getMembersAndWatchers = () => {\n const memberUsers = Object.values(this.channel.state.members ?? {}).map(\n ({ user }) => user,\n );\n const watcherUsers = Object.values(this.channel.state.watchers ?? {});\n const users = [...memberUsers, ...watcherUsers];\n\n const uniqueUsers = {} as Record<string, UserResponse>;\n\n users.forEach((user) => {\n if (user && !uniqueUsers[user.id]) {\n uniqueUsers[user.id] = user;\n }\n });\n\n return Object.values(uniqueUsers);\n };\n\n searchMembersLocally = (searchQuery: string) => {\n const { textComposerText } = this.config;\n if (!textComposerText) return [];\n\n return this.getMembersAndWatchers()\n .filter((user) => {\n if (user.id === this.client.userID) return false;\n if (!searchQuery) return true;\n\n const updatedId = this.transliterate(removeDiacritics(user.id)).toLowerCase();\n const updatedName = this.transliterate(removeDiacritics(user.name)).toLowerCase();\n const updatedQuery = this.transliterate(\n removeDiacritics(searchQuery),\n ).toLowerCase();\n\n const maxDistance = 3;\n const lastDigits = textComposerText.slice(-(maxDistance + 1)).includes('@');\n\n if (updatedName) {\n const levenshtein = calculateLevenshtein(updatedQuery, updatedName);\n if (\n updatedName.includes(updatedQuery) ||\n (levenshtein <= maxDistance && lastDigits)\n ) {\n return true;\n }\n }\n\n const levenshtein = calculateLevenshtein(updatedQuery, updatedId);\n\n return (\n updatedId.includes(updatedQuery) || (levenshtein <= maxDistance && lastDigits)\n );\n })\n .sort((a, b) => {\n if (!this.memberSort) return (a.name || '').localeCompare(b.name || '');\n\n // Apply each sort criteria in order\n for (const [field, direction] of Object.entries(this.memberSort)) {\n const aValue = a[field as keyof UserResponse];\n const bValue = b[field as keyof UserResponse];\n\n if (aValue === bValue) continue;\n return direction === 1\n ? String(aValue || '').localeCompare(String(bValue || ''))\n : String(bValue || '').localeCompare(String(aValue || ''));\n }\n return 0;\n });\n };\n\n prepareQueryUsersParams = (searchQuery: string) => ({\n filters: {\n $or: [\n { id: { $autocomplete: searchQuery } },\n { name: { $autocomplete: searchQuery } },\n ],\n ...this.userFilters,\n } as UserFilters,\n sort: this.userSort ?? ([{ name: 1 }, { id: 1 }] as UserSort), // todo: document the change - the sort is overridden, not merged\n options: { ...this.searchOptions, limit: this.pageSize, offset: this.offset },\n });\n\n prepareQueryMembersParams = (searchQuery: string) => {\n // QueryMembers failed with error: \\\"sort must contain at maximum 1 item\\\"\n const maxSortParamsCount = 1;\n let sort: MemberSort = [{ user_id: 1 }];\n if (!this.memberSort) {\n sort = [{ user_id: 1 }];\n } else if (Array.isArray(this.memberSort)) {\n sort = this.memberSort[0];\n } else if (Object.keys(this.memberSort).length === maxSortParamsCount) {\n sort = this.memberSort;\n } // todo: document the change - the sort is overridden, not merged\n return {\n // todo: document the change - the filter is overridden, not merged\n filters:\n this.memberFilters ?? ({ name: { $autocomplete: searchQuery } } as MemberFilters), // autocomplete possible only for name\n sort,\n options: { ...this.searchOptions, limit: this.pageSize, offset: this.offset },\n };\n };\n\n queryUsers = async (searchQuery: string) => {\n const { filters, sort, options } = this.prepareQueryUsersParams(searchQuery);\n const { users } = await this.client.queryUsers(filters, sort, options);\n return users;\n };\n\n queryMembers = async (searchQuery: string) => {\n const { filters, sort, options } = this.prepareQueryMembersParams(searchQuery);\n const response = await this.channel.queryMembers(filters, sort, options);\n\n return response.members.map((member) => member.user) as UserResponse[];\n };\n\n async query(searchQuery: string) {\n let users: UserResponse[];\n const shouldSearchLocally =\n this.allMembersLoadedWithInitialChannelQuery || !searchQuery;\n\n if (this.config.mentionAllAppUsers) {\n users = await this.queryUsers(searchQuery);\n } else if (shouldSearchLocally) {\n users = this.searchMembersLocally(searchQuery);\n } else {\n users = await this.queryMembers(searchQuery);\n }\n\n return {\n items: users.map(\n (user) =>\n ({\n ...user,\n ...getTokenizedSuggestionDisplayName({\n displayName: user.name || user.id,\n searchToken: this.searchQuery,\n }),\n }) as UserSuggestion,\n ),\n };\n }\n\n filterMutes = (data: UserSuggestion[]) => {\n const { textComposerText } = this.config;\n if (!textComposerText) return [];\n\n const { mutedUsers } = this.client;\n if (textComposerText.includes('/unmute') && !mutedUsers.length) {\n return [];\n }\n if (!mutedUsers.length) return data;\n\n if (textComposerText.includes('/unmute')) {\n return data.filter((suggestion) =>\n mutedUsers.some((mute) => mute.target.id === suggestion.id),\n );\n }\n return data.filter((suggestion) =>\n mutedUsers.every((mute) => mute.target.id !== suggestion.id),\n );\n };\n\n filterQueryResults(items: UserSuggestion[]) {\n return this.filterMutes(items);\n }\n}\n\nconst DEFAULT_OPTIONS: TextComposerMiddlewareOptions = { minChars: 1, trigger: '@' };\n\nconst userSuggestionToUserResponse = (suggestion: UserSuggestion): UserResponse => {\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n const { tokenizedDisplayName, ...userResponse } = suggestion;\n return userResponse;\n};\n\n/**\n * TextComposer middleware for mentions\n * Usage:\n *\n * const textComposer = new TextComposer(options);\n *\n * textComposer.use(createMentionsMiddleware(channel, {\n * trigger: '$',\n * minChars: 2\n * }));\n *\n * @param channel\n * @param {{\n * minChars: number;\n * trigger: string;\n * }} options\n * @returns\n */\n\nexport type MentionsMiddleware = Middleware<\n TextComposerMiddlewareExecutorState<UserSuggestion>,\n 'onChange' | 'onSuggestionItemSelect'\n>;\n\nexport const createMentionsMiddleware = (\n channel: Channel,\n options?: Partial<TextComposerMiddlewareOptions> & {\n searchSource?: MentionsSearchSource;\n },\n): MentionsMiddleware => {\n const finalOptions = mergeWith(DEFAULT_OPTIONS, options ?? {});\n let searchSource: MentionsSearchSource;\n if (options?.searchSource) {\n searchSource = options.searchSource;\n searchSource.resetState();\n } else {\n searchSource = new MentionsSearchSource(channel);\n }\n searchSource.activate();\n return {\n id: 'stream-io/text-composer/mentions-middleware',\n handlers: {\n onChange: ({ state, next, complete, forward }) => {\n if (!state.selection) return forward();\n\n const triggerWithToken = getTriggerCharWithToken({\n trigger: finalOptions.trigger,\n text: state.text.slice(0, state.selection.end),\n });\n\n const newSearchTriggered =\n triggerWithToken && triggerWithToken.length === finalOptions.minChars;\n\n if (newSearchTriggered) {\n searchSource.resetStateAndActivate();\n }\n\n const triggerWasRemoved =\n !triggerWithToken || triggerWithToken.length < finalOptions.minChars;\n\n if (triggerWasRemoved) {\n const hasStaleSuggestions = state.suggestions?.trigger === finalOptions.trigger;\n const newState = { ...state };\n if (hasStaleSuggestions) {\n delete newState.suggestions;\n }\n return next(newState);\n }\n\n searchSource.config.textComposerText = state.text;\n\n return complete({\n ...state,\n suggestions: {\n query: triggerWithToken.slice(1),\n searchSource,\n trigger: finalOptions.trigger,\n },\n });\n },\n onSuggestionItemSelect: ({ state, complete, forward }) => {\n const { selectedSuggestion } = state.change ?? {};\n if (!selectedSuggestion || state.suggestions?.trigger !== finalOptions.trigger)\n return forward();\n\n searchSource.resetStateAndActivate();\n return complete({\n ...state,\n ...insertItemWithTrigger({\n insertText: `@${selectedSuggestion.name || selectedSuggestion.id} `,\n selection: state.selection,\n text: state.text,\n trigger: finalOptions.trigger,\n }),\n mentionedUsers: state.mentionedUsers.concat(\n userSuggestionToUserResponse(selectedSuggestion),\n ),\n suggestions: undefined,\n });\n },\n },\n };\n};\n", "import type { MessageComposer } from '../../messageComposer';\nimport type { TextComposerMiddlewareExecutorState } from './TextComposerMiddlewareExecutor';\nimport type { Suggestion } from './types';\nimport type { Middleware } from '../../../middleware';\n\nexport type TextComposerPreValidationMiddleware = Middleware<\n TextComposerMiddlewareExecutorState<Suggestion>,\n 'onChange' | 'onSuggestionItemSelect'\n>;\n\nexport const createTextComposerPreValidationMiddleware = (\n composer: MessageComposer,\n): TextComposerPreValidationMiddleware => ({\n id: 'stream-io/text-composer/pre-validation-middleware',\n handlers: {\n onChange: ({ state, next, forward }) => {\n const { maxLengthOnEdit } = composer.config.text ?? {};\n if (typeof maxLengthOnEdit === 'number' && state.text.length > maxLengthOnEdit) {\n state.text = state.text.slice(0, maxLengthOnEdit);\n return next({\n ...state,\n text: state.text,\n });\n }\n return forward();\n },\n onSuggestionItemSelect: ({ forward }) => forward(),\n },\n});\n", "import { createCommandsMiddleware } from './commands';\nimport { createMentionsMiddleware } from './mentions';\nimport { createTextComposerPreValidationMiddleware } from './validation';\nimport { MiddlewareExecutor } from '../../../middleware';\nimport type {\n ExecuteParams,\n MiddlewareExecutionResult,\n MiddlewareHandler,\n} from '../../../middleware';\nimport type {\n Suggestion,\n Suggestions,\n TextComposerMiddlewareExecutorOptions,\n TextComposerState,\n} from './types';\n\nexport type TextComposerMiddlewareExecutorState<T extends Suggestion = Suggestion> =\n TextComposerState<T> & {\n change?: {\n selectedSuggestion?: T;\n };\n };\n\nexport type TextComposerHandlerNames = 'onChange' | 'onSuggestionItemSelect';\n\nexport type TextComposerMiddleware<T extends Suggestion = Suggestion> = {\n id: string;\n handlers: {\n [K in TextComposerHandlerNames]: MiddlewareHandler<\n TextComposerMiddlewareExecutorState<T>\n >;\n };\n};\n\nexport class TextComposerMiddlewareExecutor<\n T extends Suggestion = Suggestion,\n> extends MiddlewareExecutor<\n TextComposerMiddlewareExecutorState<T>,\n TextComposerHandlerNames\n> {\n constructor({ composer }: TextComposerMiddlewareExecutorOptions) {\n super();\n this.use([\n createTextComposerPreValidationMiddleware(composer) as TextComposerMiddleware<T>,\n createMentionsMiddleware(composer.channel) as TextComposerMiddleware<T>,\n createCommandsMiddleware(composer.channel) as TextComposerMiddleware<T>,\n ]);\n }\n\n async execute({\n eventName,\n initialValue: initialState,\n }: ExecuteParams<TextComposerMiddlewareExecutorState<T>>): Promise<\n MiddlewareExecutionResult<TextComposerMiddlewareExecutorState<T>>\n > {\n const result = await this.executeMiddlewareChain({\n eventName,\n initialValue: initialState,\n });\n\n const { query, searchSource } = result.state.suggestions ?? ({} as Suggestions);\n /**\n * Catching error just for sanity purposes.\n * The BaseSearchSource.search() method returns debounced result.\n * That means the result of the previous search call as the debounced call result is unknown at the moment.\n * Custom search source implementation should handle errors meaningfully internally.\n */\n searchSource?.search(query)?.catch(console.error);\n\n return result;\n }\n}\n", "import { TextComposerMiddlewareExecutor } from './middleware';\nimport { StateStore } from '../store';\nimport { logChatPromiseExecution } from '../utils';\nimport type { TextComposerSuggestion } from './middleware/textComposer/types';\nimport type { TextSelection } from './middleware/textComposer/types';\nimport type { TextComposerState } from './middleware/textComposer/types';\nimport type { Suggestions } from './middleware/textComposer/types';\nimport type { MessageComposer } from './messageComposer';\nimport type { CommandResponse, DraftMessage, LocalMessage, UserResponse } from '../types';\n\nexport type TextComposerOptions = {\n composer: MessageComposer;\n message?: DraftMessage | LocalMessage;\n};\n\nexport const textIsEmpty = (text: string) => {\n const trimmedText = text.trim();\n return (\n trimmedText === '' ||\n trimmedText === '>' ||\n trimmedText === '``````' ||\n trimmedText === '``' ||\n trimmedText === '**' ||\n trimmedText === '____' ||\n trimmedText === '__' ||\n trimmedText === '****'\n );\n};\n\nconst initState = ({\n composer,\n message,\n}: {\n composer: MessageComposer;\n message?: DraftMessage | LocalMessage;\n}): TextComposerState => {\n if (!message) {\n const text = composer.config.text.defaultValue ?? '';\n return {\n command: null,\n mentionedUsers: [],\n text,\n selection: { start: text.length, end: text.length },\n };\n }\n const text = message.text ?? '';\n return {\n mentionedUsers: (message.mentioned_users ?? []).map((item: string | UserResponse) =>\n typeof item === 'string' ? ({ id: item } as UserResponse) : item,\n ),\n text,\n selection: { start: text.length, end: text.length },\n };\n};\n\nexport class TextComposer {\n readonly composer: MessageComposer;\n readonly state: StateStore<TextComposerState>;\n middlewareExecutor: TextComposerMiddlewareExecutor;\n\n constructor({ composer, message }: TextComposerOptions) {\n this.composer = composer;\n this.state = new StateStore<TextComposerState>(initState({ composer, message }));\n this.middlewareExecutor = new TextComposerMiddlewareExecutor({ composer });\n }\n\n get channel() {\n return this.composer.channel;\n }\n\n get config() {\n return this.composer.config.text;\n }\n\n get enabled() {\n return this.composer.config.text.enabled;\n }\n\n set enabled(enabled: boolean) {\n if (enabled === this.enabled) return;\n this.composer.updateConfig({ text: { enabled } });\n }\n\n get defaultValue() {\n return this.composer.config.text.defaultValue;\n }\n\n set defaultValue(defaultValue: string | undefined) {\n if (defaultValue === this.defaultValue) return;\n this.composer.updateConfig({ text: { defaultValue } });\n }\n\n get maxLengthOnEdit() {\n return this.composer.config.text.maxLengthOnEdit;\n }\n\n set maxLengthOnEdit(maxLengthOnEdit: number | undefined) {\n if (maxLengthOnEdit === this.maxLengthOnEdit) return;\n this.composer.updateConfig({ text: { maxLengthOnEdit } });\n }\n\n get maxLengthOnSend() {\n return this.composer.config.text.maxLengthOnSend;\n }\n\n set maxLengthOnSend(maxLengthOnSend: number | undefined) {\n if (maxLengthOnSend === this.maxLengthOnSend) return;\n this.composer.updateConfig({ text: { maxLengthOnSend } });\n }\n\n get publishTypingEvents() {\n return this.composer.config.text.publishTypingEvents;\n }\n\n set publishTypingEvents(publishTypingEvents: boolean) {\n if (publishTypingEvents === this.publishTypingEvents) return;\n this.composer.updateConfig({ text: { publishTypingEvents } });\n }\n\n // --- START STATE API ---\n\n get command() {\n return this.state.getLatestValue().command;\n }\n\n get mentionedUsers() {\n return this.state.getLatestValue().mentionedUsers;\n }\n\n get selection() {\n return this.state.getLatestValue().selection;\n }\n\n get suggestions() {\n return this.state.getLatestValue().suggestions;\n }\n\n get text() {\n return this.state.getLatestValue().text;\n }\n\n get textIsEmpty() {\n return textIsEmpty(this.text);\n }\n\n initState = ({ message }: { message?: DraftMessage | LocalMessage } = {}) => {\n this.state.next(initState({ composer: this.composer, message }));\n };\n\n setMentionedUsers(users: UserResponse[]) {\n this.state.partialNext({ mentionedUsers: users });\n }\n\n clearCommand() {\n this.state.partialNext({ command: null });\n }\n\n upsertMentionedUser = (user: UserResponse) => {\n const mentionedUsers = [...this.mentionedUsers];\n const existingUserIndex = mentionedUsers.findIndex((u) => u.id === user.id);\n if (existingUserIndex >= 0) {\n mentionedUsers.splice(existingUserIndex, 1, user);\n this.state.partialNext({ mentionedUsers });\n } else {\n mentionedUsers.push(user);\n this.state.partialNext({ mentionedUsers });\n }\n };\n\n getMentionedUser = (userId: string) =>\n this.state.getLatestValue().mentionedUsers.find((u: UserResponse) => u.id === userId);\n\n removeMentionedUser = (userId: string) => {\n const existingUserIndex = this.mentionedUsers.findIndex((u) => u.id === userId);\n if (existingUserIndex === -1) return;\n const mentionedUsers = [...this.mentionedUsers];\n mentionedUsers.splice(existingUserIndex, 1);\n this.state.partialNext({ mentionedUsers });\n };\n\n setCommand = (command: CommandResponse | null) => {\n if (command?.name === this.command?.name) return;\n this.state.partialNext({ command });\n };\n\n setText = (text: string) => {\n if (!this.enabled || text === this.text) return;\n this.state.partialNext({ text });\n };\n\n setSelection = (selection: TextSelection) => {\n const selectionChanged =\n selection.start !== this.selection.start || selection.end !== this.selection.end;\n if (!this.enabled || !selectionChanged) return;\n this.state.partialNext({ selection });\n };\n\n insertText = async ({\n text,\n selection,\n }: {\n text: string;\n selection?: TextSelection;\n }) => {\n if (!this.enabled) return;\n\n const finalSelection: TextSelection = selection ?? this.selection;\n const { maxLengthOnEdit } = this.composer.config.text ?? {};\n const currentText = this.text;\n const textBeforeTrim = [\n currentText.slice(0, finalSelection.start),\n text,\n currentText.slice(finalSelection.end),\n ].join('');\n\n const finalText = textBeforeTrim.slice(\n 0,\n typeof maxLengthOnEdit === 'number' ? maxLengthOnEdit : textBeforeTrim.length,\n );\n const expectedCursorPosition = finalSelection.start + text.length;\n const cursorPosition = Math.min(expectedCursorPosition, finalText.length);\n\n await this.handleChange({\n text: finalText,\n selection: {\n start: cursorPosition,\n end: cursorPosition,\n },\n });\n };\n\n wrapSelection = ({\n head = '',\n selection,\n tail = '',\n }: {\n head?: string;\n selection?: TextSelection;\n tail?: string;\n }) => {\n if (!this.enabled) return;\n const currentSelection: TextSelection = selection ?? this.selection;\n const prependedText = this.text.slice(0, currentSelection.start);\n const selectedText = this.text.slice(currentSelection.start, currentSelection.end);\n const appendedText = this.text.slice(currentSelection.end);\n const finalSelection = {\n start: prependedText.length + head.length,\n end: prependedText.length + head.length + selectedText.length,\n };\n this.state.partialNext({\n text: [prependedText, head, selectedText, tail, appendedText].join(''),\n selection: finalSelection,\n });\n };\n\n setSuggestions = (suggestions: Suggestions) => {\n this.state.partialNext({ suggestions });\n };\n\n closeSuggestions = () => {\n const { suggestions } = this.state.getLatestValue();\n if (!suggestions) return;\n this.state.partialNext({ suggestions: undefined });\n };\n // --- END STATE API ---\n\n // --- START TEXT PROCESSING ----\n\n handleChange = async ({\n text,\n selection,\n }: {\n selection: TextSelection;\n text: string;\n }) => {\n if (!this.enabled) return;\n const output = await this.middlewareExecutor.execute({\n eventName: 'onChange',\n initialValue: {\n ...this.state.getLatestValue(),\n text,\n selection,\n },\n });\n if (output.status === 'discard') return;\n this.state.next(output.state);\n\n if (this.config.publishTypingEvents && text) {\n logChatPromiseExecution(\n this.channel.keystroke(this.composer.threadId ?? undefined),\n 'start typing event',\n );\n }\n };\n\n // todo: document how to register own middleware handler to simulate onSelectUser prop\n handleSelect = async (target: TextComposerSuggestion<unknown>) => {\n if (!this.enabled) return;\n const output = await this.middlewareExecutor.execute({\n eventName: 'onSuggestionItemSelect',\n initialValue: {\n ...this.state.getLatestValue(),\n change: {\n selectedSuggestion: target,\n },\n },\n });\n if (output?.status === 'discard') return;\n this.state.next(output.state);\n };\n // --- END TEXT PROCESSING ----\n}\n", "import type { Unsubscribe } from '../store';\n\n/**\n * @private\n * Class to use as a template for subscribable entities.\n */\nexport abstract class WithSubscriptions {\n private unsubscribeFunctions: Set<Unsubscribe> = new Set();\n /**\n * Workaround for the missing TS keyword - ensures that inheritants\n * overriding `unregisterSubscriptions` call the base method and return\n * its unique symbol value.\n */\n protected static symbol = Symbol(WithSubscriptions.name);\n private refCount = 0;\n\n public abstract registerSubscriptions(): void;\n\n /**\n * Returns a boolean, provides information of whether `registerSubscriptions`\n * method has already been called for this instance.\n */\n public get hasSubscriptions() {\n return this.unsubscribeFunctions.size > 0;\n }\n\n protected addUnsubscribeFunction(unsubscribeFunction: Unsubscribe) {\n this.unsubscribeFunctions.add(unsubscribeFunction);\n }\n\n /**\n * Increments `refCount` by one and returns new value.\n */\n protected incrementRefCount() {\n return ++this.refCount;\n }\n\n /**\n * If you re-declare `unregisterSubscriptions` method within your class\n * make sure to run the original too.\n *\n * @example\n * ```ts\n * class T extends WithSubscriptions {\n * ...\n * public unregisterSubscriptions = () => {\n * this.customThing();\n * return super.unregisterSubscriptions();\n * }\n * }\n * ```\n */\n public unregisterSubscriptions(): typeof WithSubscriptions.symbol {\n if (this.refCount > 1) {\n this.refCount--;\n return WithSubscriptions.symbol;\n }\n\n this.unsubscribeFunctions.forEach((unsubscribe) => unsubscribe());\n this.unsubscribeFunctions.clear();\n this.refCount = 0;\n\n return WithSubscriptions.symbol;\n }\n}\n", "import { StateStore } from './store';\nimport {\n addToMessageList,\n findIndexInSortedArray,\n formatMessage,\n throttle,\n} from './utils';\nimport type {\n AscDesc,\n EventTypes,\n LocalMessage,\n MessagePaginationOptions,\n MessageResponse,\n ReadResponse,\n ThreadResponse,\n UserResponse,\n} from './types';\nimport type { Channel } from './channel';\nimport type { StreamChat } from './client';\nimport type { CustomThreadData } from './custom_types';\nimport { MessageComposer } from './messageComposer';\nimport { WithSubscriptions } from './utils/WithSubscriptions';\n\ntype QueryRepliesOptions = {\n sort?: { created_at: AscDesc }[];\n} & MessagePaginationOptions & { user?: UserResponse; user_id?: string };\n\nexport type ThreadState = {\n /**\n * Determines if the thread is currently opened and on-screen. When the thread is active,\n * all new messages are immediately marked as read.\n */\n active: boolean;\n channel: Channel;\n createdAt: Date;\n custom: CustomThreadData;\n deletedAt: Date | null;\n isLoading: boolean;\n isStateStale: boolean;\n pagination: ThreadRepliesPagination;\n /**\n * Thread is identified by and has a one-to-one relation with its parent message.\n * We use parent message id as a thread id.\n */\n parentMessage: LocalMessage;\n participants: ThreadResponse['thread_participants'];\n read: ThreadReadState;\n replies: Array<LocalMessage>;\n replyCount: number;\n title: string;\n updatedAt: Date | null;\n};\n\nexport type ThreadRepliesPagination = {\n isLoadingNext: boolean;\n isLoadingPrev: boolean;\n nextCursor: string | null;\n prevCursor: string | null;\n};\n\nexport type ThreadUserReadState = {\n lastReadAt: Date;\n unreadMessageCount: number;\n user: UserResponse;\n lastReadMessageId?: string;\n};\n\nexport type ThreadReadState = Record<string, ThreadUserReadState | undefined>;\n\nconst DEFAULT_PAGE_LIMIT = 50;\nconst DEFAULT_SORT: { created_at: AscDesc }[] = [{ created_at: -1 }];\nconst MARK_AS_READ_THROTTLE_TIMEOUT = 1000;\n// TODO: remove this once we move to API v2\nexport const THREAD_RESPONSE_RESERVED_KEYS: Record<keyof ThreadResponse, true> = {\n active_participant_count: true,\n channel: true,\n channel_cid: true,\n created_at: true,\n created_by: true,\n created_by_user_id: true,\n deleted_at: true,\n draft: true,\n last_message_at: true,\n latest_replies: true,\n parent_message: true,\n parent_message_id: true,\n participant_count: true,\n read: true,\n reply_count: true,\n thread_participants: true,\n title: true,\n updated_at: true,\n};\n\n// TODO: remove this once we move to API v2\nconst constructCustomDataObject = <T extends ThreadResponse>(threadData: T) => {\n const custom: CustomThreadData = {};\n\n for (const key in threadData) {\n if (THREAD_RESPONSE_RESERVED_KEYS[key as keyof ThreadResponse]) {\n continue;\n }\n\n const customKey = key as keyof CustomThreadData;\n\n custom[customKey] = threadData[customKey];\n }\n\n return custom;\n};\n\nexport class Thread extends WithSubscriptions {\n public readonly state: StateStore<ThreadState>;\n public readonly id: string;\n public readonly messageComposer: MessageComposer;\n\n private client: StreamChat;\n private failedRepliesMap: Map<string, LocalMessage> = new Map();\n\n constructor({\n client,\n threadData,\n }: {\n client: StreamChat;\n threadData: ThreadResponse;\n }) {\n super();\n\n const channel = client.channel(threadData.channel.type, threadData.channel.id, {\n // @ts-expect-error name is a \"custom\" property\n name: threadData.channel.name,\n });\n channel._hydrateMembers({\n members: threadData.channel.members ?? [],\n overrideCurrentState: false,\n });\n\n // For when read object is undefined and due to that unreadMessageCount for\n // the current user isn't being incremented on message.new\n const placeholderReadResponse: ReadResponse[] = client.userID\n ? [\n {\n user: { id: client.userID },\n unread_messages: 0,\n last_read: new Date().toISOString(),\n },\n ]\n : [];\n\n this.state = new StateStore<ThreadState>({\n // local only\n active: false,\n isLoading: false,\n isStateStale: false,\n // 99.9% should never change\n channel,\n createdAt: new Date(threadData.created_at),\n // rest\n deletedAt: threadData.deleted_at ? new Date(threadData.deleted_at) : null,\n pagination: repliesPaginationFromInitialThread(threadData),\n parentMessage: formatMessage(threadData.parent_message),\n participants: threadData.thread_participants,\n read: formatReadState(\n !threadData.read || threadData.read.length === 0\n ? placeholderReadResponse\n : threadData.read,\n ),\n replies: threadData.latest_replies.map(formatMessage),\n replyCount: threadData.reply_count ?? 0,\n updatedAt: threadData.updated_at ? new Date(threadData.updated_at) : null,\n title: threadData.title,\n custom: constructCustomDataObject(threadData),\n });\n\n this.id = threadData.parent_message_id;\n this.client = client;\n\n this.messageComposer = new MessageComposer({\n client,\n composition: threadData.draft,\n compositionContext: this,\n });\n }\n\n get channel() {\n return this.state.getLatestValue().channel;\n }\n\n get hasStaleState() {\n return this.state.getLatestValue().isStateStale;\n }\n\n get ownUnreadCount() {\n return ownUnreadCountSelector(this.client.userID)(this.state.getLatestValue());\n }\n\n public activate = () => {\n this.state.partialNext({ active: true });\n };\n\n public deactivate = () => {\n this.state.partialNext({ active: false });\n };\n\n public reload = async () => {\n if (this.state.getLatestValue().isLoading) {\n return;\n }\n\n this.state.partialNext({ isLoading: true });\n\n try {\n const thread = await this.client.getThread(this.id, { watch: true });\n this.hydrateState(thread);\n } finally {\n this.state.partialNext({ isLoading: false });\n }\n };\n\n public hydrateState = (thread: Thread) => {\n if (thread === this) {\n // skip if the instances are the same\n return;\n }\n\n if (thread.id !== this.id) {\n throw new Error(\n \"Cannot hydrate thread's state using thread with different threadId\",\n );\n }\n\n const {\n createdAt,\n custom,\n title,\n deletedAt,\n parentMessage,\n participants,\n read,\n replyCount,\n replies,\n updatedAt,\n } = thread.state.getLatestValue();\n\n // Preserve pending replies and append them to the updated list of replies\n const pendingReplies = Array.from(this.failedRepliesMap.values());\n\n this.state.partialNext({\n title,\n createdAt,\n custom,\n deletedAt,\n parentMessage,\n participants,\n read,\n replyCount,\n replies: pendingReplies.length ? replies.concat(pendingReplies) : replies,\n updatedAt,\n isStateStale: false,\n });\n };\n\n public registerSubscriptions = () => {\n if (this.hasSubscriptions) {\n // Thread is already listening for events and changes\n return;\n }\n\n this.addUnsubscribeFunction(this.subscribeThreadUpdated());\n this.addUnsubscribeFunction(this.subscribeMarkActiveThreadRead());\n this.addUnsubscribeFunction(this.subscribeReloadActiveStaleThread());\n this.addUnsubscribeFunction(this.subscribeMarkThreadStale());\n this.addUnsubscribeFunction(this.subscribeNewReplies());\n this.addUnsubscribeFunction(this.subscribeRepliesRead());\n this.addUnsubscribeFunction(this.subscribeMessageDeleted());\n this.addUnsubscribeFunction(this.subscribeMessageUpdated());\n };\n\n private subscribeThreadUpdated = () =>\n this.client.on('thread.updated', (event) => {\n if (!event.thread || event.thread.parent_message_id !== this.id) {\n return;\n }\n\n const threadData = event.thread;\n\n this.state.partialNext({\n title: threadData.title,\n updatedAt: new Date(threadData.updated_at),\n deletedAt: threadData.deleted_at ? new Date(threadData.deleted_at) : null,\n // TODO: use threadData.custom once we move to API v2\n custom: constructCustomDataObject(threadData),\n });\n }).unsubscribe;\n\n private subscribeMarkActiveThreadRead = () =>\n this.state.subscribeWithSelector(\n (nextValue) => ({\n active: nextValue.active,\n unreadMessageCount: ownUnreadCountSelector(this.client.userID)(nextValue),\n }),\n ({ active, unreadMessageCount }) => {\n if (!active || !unreadMessageCount) return;\n this.throttledMarkAsRead();\n },\n );\n\n private subscribeReloadActiveStaleThread = () =>\n this.state.subscribeWithSelector(\n (nextValue) => ({ active: nextValue.active, isStateStale: nextValue.isStateStale }),\n ({ active, isStateStale }) => {\n if (active && isStateStale) {\n this.reload();\n }\n },\n );\n\n private subscribeMarkThreadStale = () =>\n this.client.on('user.watching.stop', (event) => {\n const { channel } = this.state.getLatestValue();\n\n if (\n !this.client.userID ||\n this.client.userID !== event.user?.id ||\n event.channel?.cid !== channel.cid\n ) {\n return;\n }\n\n this.state.partialNext({ isStateStale: true });\n }).unsubscribe;\n\n private subscribeNewReplies = () =>\n this.client.on('message.new', (event) => {\n if (!this.client.userID || event.message?.parent_id !== this.id) {\n return;\n }\n\n const isOwnMessage = event.message.user?.id === this.client.userID;\n const { active, read } = this.state.getLatestValue();\n\n this.upsertReplyLocally({\n message: event.message,\n // Message from current user could have been added optimistically,\n // so the actual timestamp might differ in the event\n timestampChanged: isOwnMessage,\n });\n\n if (active) {\n this.throttledMarkAsRead();\n }\n\n const nextRead: ThreadReadState = {};\n\n for (const userId of Object.keys(read)) {\n const userRead = read[userId];\n\n if (userRead) {\n let nextUserRead: ThreadUserReadState = userRead;\n\n if (userId === event.user?.id) {\n // The user who just sent a message to the thread has no unread messages\n // in that thread\n nextUserRead = {\n ...nextUserRead,\n lastReadAt: event.created_at ? new Date(event.created_at) : new Date(),\n user: event.user,\n unreadMessageCount: 0,\n };\n } else if (active && userId === this.client.userID) {\n // Do not increment unread count for the current user in an active thread\n } else {\n // Increment unread count for all users except the author of the new message\n nextUserRead = {\n ...nextUserRead,\n unreadMessageCount: userRead.unreadMessageCount + 1,\n };\n }\n\n nextRead[userId] = nextUserRead;\n }\n }\n\n this.state.partialNext({ read: nextRead });\n }).unsubscribe;\n\n private subscribeRepliesRead = () =>\n this.client.on('message.read', (event) => {\n if (!event.user || !event.created_at || !event.thread) return;\n if (event.thread.parent_message_id !== this.id) return;\n\n const userId = event.user.id;\n const createdAt = event.created_at;\n const user = event.user;\n\n this.state.next((current) => ({\n ...current,\n read: {\n ...current.read,\n [userId]: {\n lastReadAt: new Date(createdAt),\n user,\n lastReadMessageId: event.last_read_message_id,\n unreadMessageCount: 0,\n },\n },\n }));\n }).unsubscribe;\n\n private subscribeMessageDeleted = () =>\n this.client.on('message.deleted', (event) => {\n if (!event.message) return;\n\n // Deleted message is a reply of this thread\n if (event.message.parent_id === this.id) {\n if (event.hard_delete) {\n this.deleteReplyLocally({ message: event.message });\n } else {\n // Handle soft delete (updates deleted_at timestamp)\n this.upsertReplyLocally({ message: event.message });\n }\n }\n\n // Deleted message is parent message of this thread\n if (event.message.id === this.id) {\n this.updateParentMessageLocally({ message: event.message });\n }\n }).unsubscribe;\n\n private subscribeMessageUpdated = () => {\n const eventTypes: EventTypes[] = [\n 'message.updated',\n 'reaction.new',\n 'reaction.deleted',\n 'reaction.updated',\n ];\n\n const unsubscribeFunctions = eventTypes.map(\n (eventType) =>\n this.client.on(eventType, (event) => {\n if (event.message) {\n this.updateParentMessageOrReplyLocally(event.message);\n }\n }).unsubscribe,\n );\n\n return () => unsubscribeFunctions.forEach((unsubscribe) => unsubscribe());\n };\n\n public unregisterSubscriptions = () => {\n const symbol = super.unregisterSubscriptions();\n this.state.partialNext({ isStateStale: true });\n return symbol;\n };\n\n public deleteReplyLocally = ({ message }: { message: MessageResponse }) => {\n const { replies } = this.state.getLatestValue();\n\n const index = findIndexInSortedArray({\n needle: formatMessage(message),\n sortedArray: replies,\n sortDirection: 'ascending',\n selectValueToCompare: (reply) => reply.created_at.getTime(),\n selectKey: (reply) => reply.id,\n });\n\n if (replies[index]?.id !== message.id) {\n return;\n }\n\n const updatedReplies = [...replies];\n updatedReplies.splice(index, 1);\n\n this.state.partialNext({\n replies: updatedReplies,\n });\n };\n\n public upsertReplyLocally = ({\n message,\n timestampChanged = false,\n }: {\n message: MessageResponse | LocalMessage;\n timestampChanged?: boolean;\n }) => {\n if (message.parent_id !== this.id) {\n throw new Error('Reply does not belong to this thread');\n }\n\n const formattedMessage = formatMessage(message);\n\n if (message.status === 'failed') {\n // store failed reply so that it's not lost when reloading or hydrating\n this.failedRepliesMap.set(formattedMessage.id, formattedMessage);\n } else if (this.failedRepliesMap.has(message.id)) {\n this.failedRepliesMap.delete(message.id);\n }\n\n this.state.next((current) => ({\n ...current,\n replies: addToMessageList(current.replies, formattedMessage, timestampChanged),\n }));\n };\n\n public updateParentMessageLocally = ({ message }: { message: MessageResponse }) => {\n if (message.id !== this.id) {\n throw new Error('Message does not belong to this thread');\n }\n\n this.state.next((current) => {\n const formattedMessage = formatMessage(message);\n\n return {\n ...current,\n deletedAt: formattedMessage.deleted_at,\n parentMessage: formattedMessage,\n replyCount: message.reply_count ?? current.replyCount,\n };\n });\n };\n\n public updateParentMessageOrReplyLocally = (message: MessageResponse) => {\n if (message.parent_id === this.id) {\n this.upsertReplyLocally({ message });\n }\n\n if (!message.parent_id && message.id === this.id) {\n this.updateParentMessageLocally({ message });\n }\n };\n\n public markAsRead = async ({ force = false }: { force?: boolean } = {}) => {\n if (this.ownUnreadCount === 0 && !force) {\n return null;\n }\n\n return await this.channel.markRead({ thread_id: this.id });\n };\n\n private throttledMarkAsRead = throttle(\n () => this.markAsRead(),\n MARK_AS_READ_THROTTLE_TIMEOUT,\n { trailing: true },\n );\n\n public queryReplies = ({\n limit = DEFAULT_PAGE_LIMIT,\n sort = DEFAULT_SORT,\n ...otherOptions\n }: QueryRepliesOptions = {}) =>\n this.channel.getReplies(this.id, { limit, ...otherOptions }, sort);\n\n public loadNextPage = ({ limit = DEFAULT_PAGE_LIMIT }: { limit?: number } = {}) =>\n this.loadPage(limit);\n\n public loadPrevPage = ({ limit = DEFAULT_PAGE_LIMIT }: { limit?: number } = {}) =>\n this.loadPage(-limit);\n\n private loadPage = async (count: number) => {\n const { pagination } = this.state.getLatestValue();\n const [loadingKey, cursorKey, insertionMethodKey] =\n count > 0\n ? (['isLoadingNext', 'nextCursor', 'push'] as const)\n : (['isLoadingPrev', 'prevCursor', 'unshift'] as const);\n\n if (pagination[loadingKey] || pagination[cursorKey] === null) return;\n\n const queryOptions = { [count > 0 ? 'id_gt' : 'id_lt']: pagination[cursorKey] };\n const limit = Math.abs(count);\n\n this.state.partialNext({ pagination: { ...pagination, [loadingKey]: true } });\n\n try {\n const data = await this.queryReplies({ ...queryOptions, limit });\n const replies = data.messages.map(formatMessage);\n const maybeNextCursor = replies.at(count > 0 ? -1 : 0)?.id ?? null;\n\n this.state.next((current) => {\n let nextReplies = current.replies;\n\n // prevent re-creating array if there's nothing to add to the current one\n if (replies.length > 0) {\n nextReplies = [...current.replies];\n nextReplies[insertionMethodKey](...replies);\n }\n\n return {\n ...current,\n replies: nextReplies,\n pagination: {\n ...current.pagination,\n [cursorKey]: data.messages.length < limit ? null : maybeNextCursor,\n [loadingKey]: false,\n },\n };\n });\n } catch (error) {\n this.client.logger('error', (error as Error).message);\n this.state.next((current) => ({\n ...current,\n pagination: {\n ...current.pagination,\n [loadingKey]: false,\n },\n }));\n }\n };\n}\n\nconst formatReadState = (read: ReadResponse[]): ThreadReadState =>\n read.reduce<ThreadReadState>((state, userRead) => {\n state[userRead.user.id] = {\n user: userRead.user,\n lastReadMessageId: userRead.last_read_message_id,\n unreadMessageCount: userRead.unread_messages ?? 0,\n lastReadAt: new Date(userRead.last_read),\n };\n return state;\n }, {});\n\nconst repliesPaginationFromInitialThread = (\n thread: ThreadResponse,\n): ThreadRepliesPagination => {\n const latestRepliesContainsAllReplies =\n thread.latest_replies.length === thread.reply_count;\n\n return {\n nextCursor: null,\n prevCursor: latestRepliesContainsAllReplies\n ? null\n : (thread.latest_replies.at(0)?.id ?? null),\n isLoadingNext: false,\n isLoadingPrev: false,\n };\n};\n\nconst ownUnreadCountSelector =\n (currentUserId: string | undefined) => (state: ThreadState) =>\n (currentUserId && state.read[currentUserId]?.unreadMessageCount) || 0;\n", "import { AttachmentManager } from './attachmentManager';\nimport { CustomDataManager } from './CustomDataManager';\nimport { LinkPreviewsManager } from './linkPreviewsManager';\nimport { LocationComposer } from './LocationComposer';\nimport { PollComposer } from './pollComposer';\nimport { TextComposer } from './textComposer';\nimport { DEFAULT_COMPOSER_CONFIG } from './configuration';\nimport type { MessageComposerMiddlewareValue } from './middleware';\nimport {\n MessageComposerMiddlewareExecutor,\n MessageDraftComposerMiddlewareExecutor,\n} from './middleware';\nimport type { Unsubscribe } from '../store';\nimport { StateStore } from '../store';\nimport { formatMessage, generateUUIDv4, isLocalMessage, unformatMessage } from '../utils';\nimport { mergeWith } from '../utils/mergeWith';\nimport { Channel } from '../channel';\nimport { Thread } from '../thread';\nimport type {\n ChannelAPIResponse,\n DraftMessage,\n DraftResponse,\n EventTypes,\n LocalMessage,\n LocalMessageBase,\n MessageResponse,\n MessageResponseBase,\n} from '../types';\nimport { WithSubscriptions } from '../utils/WithSubscriptions';\nimport type { StreamChat } from '../client';\nimport type { MessageComposerConfig } from './configuration/types';\nimport type { DeepPartial } from '../types.utility';\nimport type { MergeWithCustomizer } from '../utils/mergeWith/mergeWithCore';\n\ntype UnregisterSubscriptions = Unsubscribe;\n\nexport type LastComposerChange = { draftUpdate: number | null; stateUpdate: number };\n\nexport type EditingAuditState = {\n lastChange: LastComposerChange;\n};\n\nexport type LocalMessageWithLegacyThreadId = LocalMessage & { legacyThreadId?: string };\nexport type CompositionContext = Channel | Thread | LocalMessageWithLegacyThreadId;\n\nexport type MessageComposerState = {\n id: string;\n draftId: string | null;\n pollId: string | null;\n quotedMessage: LocalMessageBase | null;\n showReplyInChannel: boolean;\n};\n\nexport type MessageComposerOptions = {\n client: StreamChat;\n // composer can belong to a channel, thread, legacy thread or a local message (edited message)\n compositionContext: CompositionContext;\n // initial state like draft message or edited message\n composition?: DraftResponse | MessageResponse | LocalMessage;\n config?: DeepPartial<MessageComposerConfig>;\n};\n\nconst compositionIsDraftResponse = (composition: unknown): composition is DraftResponse =>\n !!(composition as { message?: DraftMessage })?.message;\n\nconst initEditingAuditState = (\n composition?: DraftResponse | MessageResponse | LocalMessage,\n): EditingAuditState => {\n let draftUpdate = null;\n let stateUpdate = new Date().getTime();\n if (compositionIsDraftResponse(composition)) {\n stateUpdate = draftUpdate = new Date(composition.created_at).getTime();\n } else if (composition && isLocalMessage(composition)) {\n stateUpdate = new Date(composition.updated_at).getTime();\n }\n return {\n lastChange: {\n draftUpdate,\n stateUpdate,\n },\n };\n};\n\nconst initState = (\n composition?: DraftResponse | MessageResponse | LocalMessage,\n): MessageComposerState => {\n if (!composition) {\n return {\n draftId: null,\n id: MessageComposer.generateId(),\n pollId: null,\n quotedMessage: null,\n showReplyInChannel: false,\n };\n }\n\n const quotedMessage = composition.quoted_message;\n let message;\n let draftId = null;\n let id = MessageComposer.generateId(); // do not use draft id for messsage id\n if (compositionIsDraftResponse(composition)) {\n message = composition.message;\n draftId = composition.message.id;\n } else {\n message = composition;\n id = composition.id;\n }\n\n return {\n draftId,\n id,\n pollId: message.poll_id ?? null,\n quotedMessage: quotedMessage\n ? formatMessage(quotedMessage as MessageResponseBase)\n : null,\n showReplyInChannel: false,\n };\n};\n\nexport class MessageComposer extends WithSubscriptions {\n readonly channel: Channel;\n readonly state: StateStore<MessageComposerState>;\n readonly editingAuditState: StateStore<EditingAuditState>;\n readonly configState: StateStore<MessageComposerConfig>;\n readonly compositionContext: CompositionContext;\n readonly compositionMiddlewareExecutor: MessageComposerMiddlewareExecutor;\n readonly draftCompositionMiddlewareExecutor: MessageDraftComposerMiddlewareExecutor;\n\n editedMessage?: LocalMessage;\n attachmentManager: AttachmentManager;\n linkPreviewsManager: LinkPreviewsManager;\n textComposer: TextComposer;\n pollComposer: PollComposer;\n locationComposer: LocationComposer;\n customDataManager: CustomDataManager;\n // todo: mediaRecorder: MediaRecorderController;\n\n constructor({\n composition,\n config,\n compositionContext,\n client,\n }: MessageComposerOptions) {\n super();\n\n this.compositionContext = compositionContext;\n\n // channel is easily inferable from the context\n if (compositionContext instanceof Channel) {\n this.channel = compositionContext;\n } else if (compositionContext instanceof Thread) {\n this.channel = compositionContext.channel;\n } else if (compositionContext.cid) {\n const [type, id] = compositionContext.cid.split(':');\n this.channel = client.channel(type, id);\n } else {\n throw new Error(\n 'MessageComposer requires composition context pointing to channel (channel or context.cid)',\n );\n }\n\n const mergeChannelConfigCustomizer: MergeWithCustomizer<\n DeepPartial<MessageComposerConfig>\n > = (originalVal, channelConfigVal, key) =>\n typeof originalVal === 'object'\n ? undefined\n : originalVal === false && key === 'enabled' // prevent enabling features that are disabled client-side\n ? false\n : ['string', 'number', 'bigint', 'boolean', 'symbol'].includes(\n // prevent enabling features that are disabled server-side\n typeof channelConfigVal,\n )\n ? channelConfigVal // scalar values get overridden by server-side config\n : originalVal;\n\n this.configState = new StateStore<MessageComposerConfig>(\n mergeWith(\n mergeWith(DEFAULT_COMPOSER_CONFIG, config ?? {}),\n {\n location: {\n enabled: this.channel.getConfig()?.shared_locations,\n },\n },\n mergeChannelConfigCustomizer,\n ),\n );\n\n let message: LocalMessage | DraftMessage | undefined = undefined;\n if (compositionIsDraftResponse(composition)) {\n message = composition.message;\n } else if (composition) {\n message = formatMessage(composition);\n this.editedMessage = message;\n }\n\n this.attachmentManager = new AttachmentManager({ composer: this, message });\n this.linkPreviewsManager = new LinkPreviewsManager({ composer: this, message });\n this.locationComposer = new LocationComposer({ composer: this, message });\n this.textComposer = new TextComposer({ composer: this, message });\n this.pollComposer = new PollComposer({ composer: this });\n this.customDataManager = new CustomDataManager({ composer: this, message });\n\n this.editingAuditState = new StateStore<EditingAuditState>(\n this.initEditingAuditState(composition),\n );\n this.state = new StateStore<MessageComposerState>(initState(composition));\n\n this.compositionMiddlewareExecutor = new MessageComposerMiddlewareExecutor({\n composer: this,\n });\n this.draftCompositionMiddlewareExecutor = new MessageDraftComposerMiddlewareExecutor({\n composer: this,\n });\n }\n\n static evaluateContextType(compositionContext: CompositionContext) {\n if (compositionContext instanceof Channel) {\n return 'channel';\n }\n\n if (compositionContext instanceof Thread) {\n return 'thread';\n }\n\n if (typeof compositionContext.legacyThreadId === 'string') {\n return 'legacy_thread';\n }\n\n return 'message';\n }\n\n static constructTag(\n compositionContext: CompositionContext,\n ): `${ReturnType<typeof MessageComposer.evaluateContextType>}_${string}` {\n return `${this.evaluateContextType(compositionContext)}_${compositionContext.id}`;\n }\n\n static generateId = generateUUIDv4;\n\n get config(): MessageComposerConfig {\n return this.configState.getLatestValue();\n }\n\n get contextType() {\n return MessageComposer.evaluateContextType(this.compositionContext);\n }\n\n get tag() {\n return MessageComposer.constructTag(this.compositionContext);\n }\n\n get threadId() {\n // TODO: ideally we'd use this.contextType but type narrowing does not work for this.compositionContext\n // if (this.contextType === 'channel') {\n // const context = this.compositionContext; // context is a Channel\n // return null\n // }\n\n if (this.compositionContext instanceof Channel) {\n return null;\n }\n\n if (this.compositionContext instanceof Thread) {\n return this.compositionContext.id;\n }\n\n if (typeof this.compositionContext.legacyThreadId === 'string') {\n return this.compositionContext.legacyThreadId;\n }\n\n // check if the message is a reply, get parentMessageId\n if (typeof this.compositionContext.parent_id === 'string') {\n return this.compositionContext.parent_id;\n }\n\n return null;\n }\n\n get client() {\n return this.channel.getClient();\n }\n\n get id() {\n return this.state.getLatestValue().id;\n }\n\n get draftId() {\n return this.state.getLatestValue().draftId;\n }\n\n get lastChange() {\n return this.editingAuditState.getLatestValue().lastChange;\n }\n\n get quotedMessage() {\n return this.state.getLatestValue().quotedMessage;\n }\n\n get pollId() {\n return this.state.getLatestValue().pollId;\n }\n\n get showReplyInChannel() {\n return this.state.getLatestValue().showReplyInChannel;\n }\n\n get hasSendableData() {\n // If the offline mode is enabled, we allow sending a message if the composition is not empty.\n if (this.client.offlineDb) {\n return !this.compositionIsEmpty;\n }\n return !!(\n (!this.attachmentManager.uploadsInProgressCount &&\n (!this.textComposer.textIsEmpty ||\n this.attachmentManager.successfulUploadsCount > 0)) ||\n this.pollId ||\n !!this.locationComposer.validLocation\n );\n }\n\n get compositionIsEmpty() {\n return (\n !this.quotedMessage &&\n this.textComposer.textIsEmpty &&\n !this.attachmentManager.attachments.length &&\n !this.pollId &&\n !this.locationComposer.validLocation\n );\n }\n\n get lastChangeOriginIsLocal() {\n const initiatedWithoutDraft = this.lastChange.draftUpdate === null;\n const composingMessageFromScratch = initiatedWithoutDraft && !this.editedMessage;\n\n // does not mean that the original edited message is different from the current state\n const editedMessageWasUpdated =\n !!this.editedMessage?.updated_at &&\n new Date(this.editedMessage.updated_at).getTime() < this.lastChange.stateUpdate;\n\n const draftWasChanged =\n !!this.lastChange.draftUpdate &&\n this.lastChange.draftUpdate < this.lastChange.stateUpdate;\n\n return editedMessageWasUpdated || draftWasChanged || composingMessageFromScratch;\n }\n\n updateConfig(config: DeepPartial<MessageComposerConfig>) {\n this.configState.partialNext(mergeWith(this.config, config));\n }\n\n refreshId = () => {\n this.state.partialNext({ id: MessageComposer.generateId() });\n };\n\n initState = ({\n composition,\n }: { composition?: DraftResponse | MessageResponse | LocalMessage } = {}) => {\n this.editingAuditState.partialNext(this.initEditingAuditState(composition));\n\n const message: LocalMessage | DraftMessage | undefined =\n typeof composition === 'undefined'\n ? composition\n : compositionIsDraftResponse(composition)\n ? composition.message\n : formatMessage(composition);\n this.attachmentManager.initState({ message });\n this.linkPreviewsManager.initState({ message });\n this.locationComposer.initState({ message });\n this.textComposer.initState({ message });\n this.pollComposer.initState();\n this.customDataManager.initState({ message });\n this.state.next(initState(composition));\n if (\n composition &&\n !compositionIsDraftResponse(composition) &&\n message &&\n isLocalMessage(message)\n ) {\n this.editedMessage = message;\n }\n };\n\n initStateFromChannelResponse = (channelApiResponse: ChannelAPIResponse) => {\n if (this.channel.cid !== channelApiResponse.channel.cid) {\n return;\n }\n if (channelApiResponse.draft) {\n this.initState({ composition: channelApiResponse.draft });\n } else if (this.state.getLatestValue().draftId) {\n this.clear();\n this.client.offlineDb?.executeQuerySafely(\n (db) =>\n db.deleteDraft({\n cid: this.channel.cid,\n parent_id: undefined, // makes sure that we don't delete thread drafts while upserting channels\n }),\n { method: 'deleteDraft' },\n );\n }\n };\n\n initEditingAuditState = (\n composition?: DraftResponse | MessageResponse | LocalMessage,\n ) => initEditingAuditState(composition);\n\n private logStateUpdateTimestamp() {\n this.editingAuditState.partialNext({\n lastChange: { ...this.lastChange, stateUpdate: new Date().getTime() },\n });\n }\n\n private logDraftUpdateTimestamp() {\n if (!this.config.drafts.enabled) return;\n const timestamp = new Date().getTime();\n this.editingAuditState.partialNext({\n lastChange: { draftUpdate: timestamp, stateUpdate: timestamp },\n });\n }\n\n public registerDraftEventSubscriptions = () => {\n const unsubscribeDraftUpdated = this.subscribeDraftUpdated();\n const unsubscribeDraftDeleted = this.subscribeDraftDeleted();\n\n return () => {\n unsubscribeDraftUpdated();\n unsubscribeDraftDeleted();\n };\n };\n\n public registerSubscriptions = (): UnregisterSubscriptions => {\n if (!this.hasSubscriptions) {\n this.addUnsubscribeFunction(this.subscribeMessageComposerSetupStateChange());\n this.addUnsubscribeFunction(this.subscribeMessageUpdated());\n this.addUnsubscribeFunction(this.subscribeMessageDeleted());\n\n this.addUnsubscribeFunction(this.subscribeTextComposerStateChanged());\n this.addUnsubscribeFunction(this.subscribeAttachmentManagerStateChanged());\n this.addUnsubscribeFunction(this.subscribeLinkPreviewsManagerStateChanged());\n this.addUnsubscribeFunction(this.subscribeLocationComposerStateChanged());\n this.addUnsubscribeFunction(this.subscribePollComposerStateChanged());\n this.addUnsubscribeFunction(this.subscribeCustomDataManagerStateChanged());\n this.addUnsubscribeFunction(this.subscribeMessageComposerStateChanged());\n this.addUnsubscribeFunction(this.subscribeMessageComposerConfigStateChanged());\n }\n\n this.incrementRefCount();\n\n return () => this.unregisterSubscriptions();\n };\n\n private subscribeMessageUpdated = () => {\n // todo: test the impact of 'reaction.new', 'reaction.deleted', 'reaction.updated'\n const eventTypes: EventTypes[] = [\n 'message.updated',\n 'reaction.new',\n 'reaction.deleted', // todo: do we need to subscribe to this especially when the whole state is overriden?\n 'reaction.updated', // todo: do we need to subscribe to this especially when the whole state is overriden?\n ];\n\n const unsubscribeFunctions = eventTypes.map(\n (eventType) =>\n this.client.on(eventType, (event) => {\n if (!event.message) return;\n if (event.message.id === this.id) {\n this.initState({ composition: event.message });\n }\n if (this.quotedMessage?.id && event.message.id === this.quotedMessage.id) {\n this.setQuotedMessage(formatMessage(event.message));\n }\n }).unsubscribe,\n );\n\n return () => unsubscribeFunctions.forEach((unsubscribe) => unsubscribe());\n };\n\n private subscribeMessageComposerSetupStateChange = () => {\n let tearDown: (() => void) | null = null;\n const unsubscribe = this.client._messageComposerSetupState.subscribeWithSelector(\n ({ setupFunction: setup }) => ({\n setup,\n }),\n ({ setup }) => {\n tearDown?.();\n tearDown = setup?.({ composer: this }) ?? null;\n },\n );\n\n return () => {\n tearDown?.();\n unsubscribe();\n };\n };\n\n private subscribeMessageDeleted = () =>\n this.client.on('message.deleted', (event) => {\n if (!event.message) return;\n if (event.message.id === this.id) {\n this.clear();\n } else if (this.quotedMessage && event.message.id === this.quotedMessage.id) {\n this.setQuotedMessage(null);\n }\n }).unsubscribe;\n\n private subscribeDraftUpdated = () =>\n this.client.on('draft.updated', (event) => {\n const draft = event.draft as DraftResponse;\n if (\n !draft ||\n (draft.parent_id ?? null) !== (this.threadId ?? null) ||\n draft.channel_cid !== this.channel.cid\n )\n return;\n this.initState({ composition: draft });\n }).unsubscribe;\n\n private subscribeDraftDeleted = () =>\n this.client.on('draft.deleted', (event) => {\n const draft = event.draft as DraftResponse;\n if (\n !draft ||\n (draft.parent_id ?? null) !== (this.threadId ?? null) ||\n draft.channel_cid !== this.channel.cid\n ) {\n return;\n }\n\n this.logDraftUpdateTimestamp();\n\n if (this.compositionIsEmpty) {\n return;\n }\n\n this.clear();\n }).unsubscribe;\n\n private subscribeTextComposerStateChanged = () =>\n this.textComposer.state.subscribeWithSelector(\n ({ text }) => [text] as const,\n ([currentText], previousSelection) => {\n // do not handle on initial subscription\n if (typeof previousSelection === 'undefined') return;\n\n this.logStateUpdateTimestamp();\n\n if (this.compositionIsEmpty) {\n this.deleteDraft();\n return;\n }\n\n if (!this.linkPreviewsManager.enabled) return;\n\n if (!currentText) {\n this.linkPreviewsManager.clearPreviews();\n } else {\n this.linkPreviewsManager.findAndEnrichUrls(currentText);\n }\n },\n );\n\n private subscribeAttachmentManagerStateChanged = () =>\n this.attachmentManager.state.subscribe((_, previousValue) => {\n if (typeof previousValue === 'undefined') return;\n\n this.logStateUpdateTimestamp();\n\n if (this.compositionIsEmpty) {\n this.deleteDraft();\n return;\n }\n });\n\n private subscribeLocationComposerStateChanged = () =>\n this.locationComposer.state.subscribe((_, previousValue) => {\n if (typeof previousValue === 'undefined') return;\n\n this.logStateUpdateTimestamp();\n\n if (this.compositionIsEmpty) {\n this.deleteDraft();\n return;\n }\n });\n\n private subscribeLinkPreviewsManagerStateChanged = () =>\n this.linkPreviewsManager.state.subscribe((_, previousValue) => {\n if (typeof previousValue === 'undefined') return;\n\n this.logStateUpdateTimestamp();\n\n if (this.compositionIsEmpty) {\n this.deleteDraft();\n return;\n }\n });\n\n private subscribePollComposerStateChanged = () =>\n this.pollComposer.state.subscribe((_, previousValue) => {\n if (typeof previousValue === 'undefined') return;\n\n this.logStateUpdateTimestamp();\n\n if (this.compositionIsEmpty) {\n this.deleteDraft();\n return;\n }\n });\n\n private subscribeCustomDataManagerStateChanged = () =>\n this.customDataManager.state.subscribe((nextValue, previousValue) => {\n if (\n typeof previousValue !== 'undefined' &&\n // FIXME: is this check really necessary?\n !this.customDataManager.isMessageDataEqual(nextValue, previousValue)\n ) {\n this.logStateUpdateTimestamp();\n }\n });\n\n private subscribeMessageComposerStateChanged = () =>\n this.state.subscribe((_, previousValue) => {\n if (typeof previousValue === 'undefined') return;\n\n this.logStateUpdateTimestamp();\n\n if (this.compositionIsEmpty) {\n this.deleteDraft();\n }\n });\n\n private subscribeMessageComposerConfigStateChanged = () => {\n let draftUnsubscribeFunction: Unsubscribe | null;\n\n const unsubscribe = this.configState.subscribeWithSelector(\n (currentValue) => ({\n textDefaultValue: currentValue.text.defaultValue,\n draftsEnabled: currentValue.drafts.enabled,\n }),\n ({ textDefaultValue, draftsEnabled }) => {\n if (this.textComposer.text === '' && textDefaultValue) {\n this.textComposer.insertText({\n text: textDefaultValue,\n selection: { start: 0, end: 0 },\n });\n }\n\n if (draftsEnabled && !draftUnsubscribeFunction) {\n draftUnsubscribeFunction = this.registerDraftEventSubscriptions();\n } else if (!draftsEnabled && draftUnsubscribeFunction) {\n draftUnsubscribeFunction();\n draftUnsubscribeFunction = null;\n }\n },\n );\n\n return () => {\n draftUnsubscribeFunction?.();\n unsubscribe();\n };\n };\n\n setQuotedMessage = (quotedMessage: LocalMessage | null) => {\n this.state.partialNext({ quotedMessage });\n };\n\n toggleShowReplyInChannel = () => {\n this.state.partialNext({ showReplyInChannel: !this.showReplyInChannel });\n };\n\n clear = () => {\n this.setQuotedMessage(null);\n this.initState();\n };\n\n restore = () => {\n const { editedMessage } = this;\n if (editedMessage) {\n this.initState({ composition: editedMessage });\n return;\n }\n this.clear();\n };\n\n compose = async (): Promise<MessageComposerMiddlewareValue['state'] | undefined> => {\n const created_at = this.editedMessage?.created_at ?? new Date();\n\n const text = '';\n const result = await this.compositionMiddlewareExecutor.execute({\n eventName: 'compose',\n initialValue: {\n message: {\n id: this.id,\n parent_id: this.threadId ?? undefined,\n type: 'regular',\n },\n localMessage: {\n attachments: [],\n created_at, // only assigned to localMessage as this is used for optimistic update\n deleted_at: null,\n error: undefined,\n id: this.id,\n mentioned_users: [],\n parent_id: this.threadId ?? undefined,\n pinned_at: this.editedMessage?.pinned_at || null,\n reaction_groups: null,\n status: this.editedMessage ? this.editedMessage.status : 'sending',\n text,\n type: 'regular',\n updated_at: created_at,\n },\n sendOptions: {},\n },\n });\n\n if (result.status === 'discard') return;\n\n return result.state;\n };\n\n composeDraft = async () => {\n const { state, status } = await this.draftCompositionMiddlewareExecutor.execute({\n eventName: 'compose',\n initialValue: {\n draft: { id: this.id, parent_id: this.threadId ?? undefined, text: '' },\n },\n });\n if (status === 'discard') return;\n\n return state;\n };\n\n createDraft = async () => {\n // server-side drafts are not stored on message level but on thread and channel level\n // therefore we don't need to create a draft if the message is edited\n if (this.editedMessage || !this.config.drafts.enabled) return;\n const composition = await this.composeDraft();\n if (!composition) return;\n const { draft } = composition;\n this.state.partialNext({ draftId: draft.id });\n if (this.client.offlineDb) {\n try {\n const optimisticDraftResponse = {\n channel_cid: this.channel.cid,\n created_at: new Date().toISOString(),\n message: draft as DraftMessage,\n parent_id: draft.parent_id,\n quoted_message: this.quotedMessage\n ? unformatMessage(this.quotedMessage)\n : undefined,\n };\n await this.client.offlineDb.upsertDraft({ draft: optimisticDraftResponse });\n } catch (error) {\n this.client.logger('error', `offlineDb:upsertDraft`, {\n tags: ['channel', 'offlineDb'],\n error,\n });\n }\n }\n this.logDraftUpdateTimestamp();\n await this.channel.createDraft(draft);\n };\n\n deleteDraft = async () => {\n if (this.editedMessage || !this.config.drafts.enabled || !this.draftId) return;\n this.state.partialNext({ draftId: null }); // todo: should we clear the whole state?\n const parentId = this.threadId ?? undefined;\n if (this.client.offlineDb) {\n try {\n await this.client.offlineDb.deleteDraft({\n cid: this.channel.cid,\n parent_id: parentId,\n });\n } catch (error) {\n this.client.logger('error', `offlineDb:deleteDraft`, {\n tags: ['channel', 'offlineDb'],\n error,\n });\n }\n }\n this.logDraftUpdateTimestamp();\n await this.channel.deleteDraft({ parent_id: parentId });\n };\n\n getDraft = async () => {\n if (this.editedMessage || !this.config.drafts.enabled || !this.client.userID) return;\n\n const draftFromOfflineDB = await this.client.offlineDb?.getDraft({\n cid: this.channel.cid,\n userId: this.client.userID,\n parent_id: this.threadId ?? undefined,\n });\n\n if (draftFromOfflineDB) {\n this.initState({ composition: draftFromOfflineDB });\n }\n\n try {\n const response = await this.channel.getDraft({\n parent_id: this.threadId ?? undefined,\n });\n\n const { draft } = response;\n\n if (!draft) return;\n\n this.client.offlineDb?.executeQuerySafely(\n (db) =>\n db.upsertDraft({\n draft,\n }),\n { method: 'upsertDraft' },\n );\n\n this.initState({ composition: draft });\n } catch (error) {\n this.client.notifications.add({\n message: 'Failed to get the draft',\n origin: {\n emitter: 'MessageComposer',\n context: { composer: this },\n },\n });\n }\n };\n\n createPoll = async () => {\n const composition = await this.pollComposer.compose();\n if (!composition || !composition.data.id) return;\n try {\n const poll = await this.client.polls.createPoll(composition.data);\n this.state.partialNext({ pollId: poll?.id });\n } catch (error) {\n this.client.notifications.addError({\n message: 'Failed to create the poll',\n origin: {\n emitter: 'MessageComposer',\n context: { composer: this },\n },\n options: {\n type: 'api:poll:create:failed',\n metadata: {\n reason: (error as Error).message,\n },\n originalError: error instanceof Error ? error : undefined,\n },\n });\n throw error;\n }\n };\n\n sendLocation = async () => {\n const location = this.locationComposer.validLocation;\n if (this.threadId || !location) return;\n try {\n await this.channel.sendSharedLocation(location);\n this.refreshId();\n this.locationComposer.initState();\n } catch (error) {\n this.client.notifications.addError({\n message: 'Failed to share the location',\n origin: {\n emitter: 'MessageComposer',\n context: { composer: this },\n },\n options: {\n type: 'api:location:create:failed',\n metadata: {\n reason: (error as Error).message,\n },\n originalError: error instanceof Error ? error : undefined,\n },\n });\n throw error;\n }\n };\n}\n", "import { ChannelState } from './channel_state';\nimport {\n generateChannelTempCid,\n logChatPromiseExecution,\n messageSetPagination,\n normalizeQuerySort,\n} from './utils';\nimport type { StreamChat } from './client';\nimport { DEFAULT_QUERY_CHANNEL_MESSAGE_LIST_PAGE_SIZE } from './constants';\nimport type {\n AIState,\n APIResponse,\n AscDesc,\n BanUserOptions,\n ChannelAPIResponse,\n ChannelData,\n ChannelFilters,\n ChannelMemberAPIResponse,\n ChannelMemberResponse,\n ChannelQueryOptions,\n ChannelResponse,\n ChannelUpdateOptions,\n CreateDraftResponse,\n DeleteChannelAPIResponse,\n DraftMessagePayload,\n Event,\n EventAPIResponse,\n EventHandler,\n EventTypes,\n GetDraftResponse,\n GetMultipleMessagesAPIResponse,\n GetReactionsAPIResponse,\n GetRepliesAPIResponse,\n LiveLocationPayload,\n LocalMessage,\n MarkReadOptions,\n MarkUnreadOptions,\n MemberFilters,\n MemberSort,\n Message,\n MessageFilters,\n MessageOptions,\n MessagePaginationOptions,\n MessageResponse,\n MessageSetType,\n MuteChannelAPIResponse,\n NewMemberPayload,\n PartialUpdateChannel,\n PartialUpdateChannelAPIResponse,\n PartialUpdateMember,\n PartialUpdateMemberAPIResponse,\n PinnedMessagePaginationOptions,\n PinnedMessagesSort,\n PollVoteData,\n PushPreference,\n QueryChannelAPIResponse,\n QueryMembersOptions,\n Reaction,\n ReactionAPIResponse,\n SearchAPIResponse,\n SearchMessageSortBase,\n SearchOptions,\n SearchPayload,\n SendMessageAPIResponse,\n SendMessageOptions,\n SendReactionOptions,\n StaticLocationPayload,\n TruncateChannelAPIResponse,\n TruncateOptions,\n UpdateChannelAPIResponse,\n UpdateChannelOptions,\n UpdateLocationPayload,\n UserResponse,\n} from './types';\nimport type { Role } from './permissions';\nimport type { CustomChannelData } from './custom_types';\nimport { MessageComposer } from './messageComposer';\n\n/**\n * Channel - The Channel class manages it's own state.\n */\nexport class Channel {\n _client: StreamChat;\n type: string;\n id: string | undefined;\n data: Partial<ChannelData & ChannelResponse> | undefined;\n _data: Partial<ChannelData & ChannelResponse>;\n cid: string;\n /** */\n listeners: { [key: string]: (string | EventHandler)[] };\n state: ChannelState;\n /**\n * This boolean is a vague indication of weather the channel exists on chat backend.\n *\n * If the value is true, then that means the channel has been initialized by either calling\n * channel.create() or channel.query() or channel.watch().\n *\n * If the value is false, then channel may or may not exist on the backend. The only way to ensure\n * is by calling channel.create() or channel.query() or channel.watch().\n */\n initialized: boolean;\n /**\n * Indicates weather channel has been initialized by manually populating the state with some messages, members etc.\n * Static state indicates that channel exists on backend, but is not being watched yet.\n */\n offlineMode: boolean;\n lastKeyStroke?: Date;\n lastTypingEvent: Date | null;\n isTyping: boolean;\n disconnected: boolean;\n push_preferences?: PushPreference;\n public readonly messageComposer: MessageComposer;\n\n /**\n * constructor - Create a channel\n *\n * @param {StreamChat} client the chat client\n * @param {string} type the type of channel\n * @param {string} [id] the id of the chat\n * @param {ChannelData} data any additional custom params\n *\n * @return {Channel} Returns a new uninitialized channel\n */\n constructor(\n client: StreamChat,\n type: string,\n id: string | undefined,\n data: ChannelData,\n ) {\n const validTypeRe = /^[\\w_-]+$/;\n const validIDRe = /^[\\w!_-]+$/;\n\n if (!validTypeRe.test(type)) {\n throw new Error(`Invalid chat type ${type}, letters, numbers and \"_-\" are allowed`);\n }\n if (typeof id === 'string' && !validIDRe.test(id)) {\n throw new Error(`Invalid chat id ${id}, letters, numbers and \"!-_\" are allowed`);\n }\n\n this._client = client;\n this.type = type;\n this.id = id;\n // used by the frontend, gets updated:\n this.data = data;\n // this._data is used for the requests...\n this._data = { ...data };\n this.cid = `${type}:${id}`;\n this.listeners = {};\n // perhaps the state variable should be private\n this.state = new ChannelState(this);\n this.initialized = false;\n this.offlineMode = false;\n this.lastTypingEvent = null;\n this.isTyping = false;\n this.disconnected = false;\n\n this.messageComposer = new MessageComposer({\n client: this._client,\n compositionContext: this,\n });\n }\n\n /**\n * getClient - Get the chat client for this channel. If client.disconnect() was called, this function will error\n *\n * @return {StreamChat}\n */\n getClient(): StreamChat {\n if (this.disconnected === true) {\n throw Error(`You can't use a channel after client.disconnect() was called`);\n }\n return this._client;\n }\n\n /**\n * getConfig - Get the config for this channel id (cid)\n *\n * @return {Record<string, unknown>}\n */\n getConfig() {\n const client = this.getClient();\n return client.configs[this.cid];\n }\n\n /**\n * sendMessage - Send a message to this channel\n *\n * @param {Message} message The Message object\n * @param {boolean} [options.skip_enrich_url] Do not try to enrich the URLs within message\n * @param {boolean} [options.skip_push] Skip sending push notifications\n * @param {boolean} [options.is_pending_message] DEPRECATED, please use `pending` instead.\n * @param {boolean} [options.pending] Make this message pending\n * @param {Record<string,string>} [options.pending_message_metadata] Metadata for the pending message\n * @param {boolean} [options.force_moderation] Apply force moderation for server-side requests\n *\n * @return {Promise<SendMessageAPIResponse>} The Server Response\n */\n async _sendMessage(message: Message, options?: SendMessageOptions) {\n return await this.getClient().post<SendMessageAPIResponse>(\n this._channelURL() + '/message',\n {\n message,\n ...options,\n },\n );\n }\n\n async sendMessage(message: Message, options?: SendMessageOptions) {\n try {\n const offlineDb = this.getClient().offlineDb;\n if (offlineDb) {\n const messageId = message.id;\n if (messageId) {\n return await offlineDb.queueTask<SendMessageAPIResponse>({\n task: {\n channelId: this.id as string,\n channelType: this.type,\n messageId,\n payload: [message, options],\n type: 'send-message',\n },\n });\n }\n }\n } catch (error) {\n this._client.logger('error', `offlineDb:send-message`, {\n tags: ['channel', 'offlineDb'],\n error,\n });\n }\n return await this._sendMessage(message, options);\n }\n\n sendFile(\n uri: string | NodeJS.ReadableStream | Buffer | File,\n name?: string,\n contentType?: string,\n user?: UserResponse,\n ) {\n return this.getClient().sendFile(\n `${this._channelURL()}/file`,\n uri,\n name,\n contentType,\n user,\n );\n }\n\n sendImage(\n uri: string | NodeJS.ReadableStream | File,\n name?: string,\n contentType?: string,\n user?: UserResponse,\n ) {\n return this.getClient().sendFile(\n `${this._channelURL()}/image`,\n uri,\n name,\n contentType,\n user,\n );\n }\n\n deleteFile(url: string) {\n return this.getClient().delete<APIResponse>(`${this._channelURL()}/file`, { url });\n }\n\n deleteImage(url: string) {\n return this.getClient().delete<APIResponse>(`${this._channelURL()}/image`, { url });\n }\n\n /**\n * sendEvent - Send an event on this channel\n *\n * @param {Event} event for example {type: 'message.read'}\n *\n * @return {Promise<EventAPIResponse>} The Server Response\n */\n async sendEvent(event: Event) {\n this._checkInitialized();\n return await this.getClient().post<EventAPIResponse>(this._channelURL() + '/event', {\n event,\n });\n }\n\n /**\n * search - Query messages\n *\n * @param {MessageFilters | string} query search query or object MongoDB style filters\n * @param {{client_id?: string; connection_id?: string; query?: string; message_filter_conditions?: MessageFilters}} options Option object, {user_id: 'tommaso'}\n *\n * @return {Promise<SearchAPIResponse>} search messages response\n */\n async search(\n query: MessageFilters | string,\n options: SearchOptions & {\n client_id?: string;\n connection_id?: string;\n message_filter_conditions?: MessageFilters;\n message_options?: MessageOptions;\n query?: string;\n } = {},\n ) {\n if (options.offset && options.next) {\n throw Error(`Cannot specify offset with next`);\n }\n // Return a list of channels\n const payload: SearchPayload = {\n filter_conditions: { cid: this.cid } as ChannelFilters,\n ...options,\n sort: options.sort\n ? normalizeQuerySort<SearchMessageSortBase>(options.sort)\n : undefined,\n };\n if (typeof query === 'string') {\n payload.query = query;\n } else if (typeof query === 'object') {\n payload.message_filter_conditions = query;\n } else {\n throw Error(`Invalid type ${typeof query} for query parameter`);\n }\n // Make sure we wait for the connect promise if there is a pending one\n await this.getClient().wsPromise;\n\n return await this.getClient().get<SearchAPIResponse>(\n this.getClient().baseURL + '/search',\n {\n payload,\n },\n );\n }\n\n /**\n * queryMembers - Query Members\n *\n * @param {MemberFilters} filterConditions object MongoDB style filters\n * @param {MemberSort} [sort] Sort options, for instance [{created_at: -1}].\n * When using multiple fields, make sure you use array of objects to guarantee field order, for instance [{name: -1}, {created_at: 1}]\n * @param {{ limit?: number; offset?: number }} [options] Option object, {limit: 10, offset:10}\n *\n * @return {Promise<ChannelMemberAPIResponse>} Query Members response\n */\n async queryMembers(\n filterConditions: MemberFilters,\n sort: MemberSort = [],\n options: QueryMembersOptions = {},\n ) {\n let id: string | undefined;\n const type = this.type;\n let members: string[] | ChannelMemberResponse[] | undefined;\n if (this.id) {\n id = this.id;\n } else if (this.data?.members && Array.isArray(this.data.members)) {\n members = this.data.members;\n }\n // Return a list of members\n return await this.getClient().get<ChannelMemberAPIResponse>(\n this.getClient().baseURL + '/members',\n {\n payload: {\n type,\n id,\n members,\n sort: normalizeQuerySort(sort),\n filter_conditions: filterConditions,\n ...options,\n },\n },\n );\n }\n\n /**\n * updateMemberPartial - Partial update a member\n *\n * @param {PartialUpdateMember} updates\n * @param {{ user_id?: string }} [options] Option object, {user_id: 'jane'} to optionally specify the user id\n\n * @return {Promise<ChannelMemberResponse>} Updated member\n */\n async updateMemberPartial(updates: PartialUpdateMember, options?: { userId?: string }) {\n const url = new URL(`${this._channelURL()}/member`);\n\n if (options?.userId) {\n url.searchParams.append('user_id', options.userId);\n }\n\n return await this.getClient().patch<PartialUpdateMemberAPIResponse>(\n url.toString(),\n updates,\n );\n }\n\n /**\n * @deprecated Use `updateMemberPartial` instead\n * partialUpdateMember - Partial update a member\n *\n * @param {string} user_id member user id\n * @param {PartialUpdateMember} updates\n *\n * @return {Promise<ChannelMemberResponse>} Updated member\n */\n async partialUpdateMember(user_id: string, updates: PartialUpdateMember) {\n if (!user_id) {\n throw Error('Please specify the user id');\n }\n\n return await this.getClient().patch<PartialUpdateMemberAPIResponse>(\n this._channelURL() + `/member/${encodeURIComponent(user_id)}`,\n updates,\n );\n }\n\n /**\n * sendReaction - Sends a reaction to a message. If offline support is enabled, it will make sure\n * that sending the reaction is queued up if it fails due to bad internet conditions and executed\n * later.\n *\n * @param {string} messageID the message id\n * @param {Reaction} reaction the reaction object for instance {type: 'love'}\n * @param {{ enforce_unique?: boolean, skip_push?: boolean }} [options] Option object, {enforce_unique: true, skip_push: true} to override any existing reaction or skip sending push notifications\n *\n * @return {Promise<ReactionAPIResponse>} The Server Response\n */\n async sendReaction(\n messageID: string,\n reaction: Reaction,\n options?: SendReactionOptions,\n ) {\n if (!messageID) {\n throw Error(`Message id is missing`);\n }\n if (!reaction || Object.keys(reaction).length === 0) {\n throw Error(`Reaction object is missing`);\n }\n\n try {\n const offlineDb = this.getClient().offlineDb;\n if (offlineDb) {\n return await offlineDb.queueTask<ReactionAPIResponse>({\n task: {\n channelId: this.id as string,\n channelType: this.type,\n messageId: messageID,\n payload: [messageID, reaction, options],\n type: 'send-reaction',\n },\n });\n }\n } catch (error) {\n this._client.logger('error', `offlineDb:send-reaction`, {\n tags: ['channel', 'offlineDb'],\n error,\n });\n }\n\n return this._sendReaction(messageID, reaction, options);\n }\n\n /**\n * sendReaction - Send a reaction about a message\n *\n * @param {string} messageID the message id\n * @param {Reaction} reaction the reaction object for instance {type: 'love'}\n * @param {{ enforce_unique?: boolean, skip_push?: boolean }} [options] Option object, {enforce_unique: true, skip_push: true} to override any existing reaction or skip sending push notifications\n *\n * @return {Promise<ReactionAPIResponse>} The Server Response\n */\n async _sendReaction(\n messageID: string,\n reaction: Reaction,\n options?: SendReactionOptions,\n ) {\n if (!messageID) {\n throw Error(`Message id is missing`);\n }\n if (!reaction || Object.keys(reaction).length === 0) {\n throw Error(`Reaction object is missing`);\n }\n\n return await this.getClient().post<ReactionAPIResponse>(\n this.getClient().baseURL + `/messages/${encodeURIComponent(messageID)}/reaction`,\n {\n reaction,\n ...options,\n },\n );\n }\n\n async deleteReaction(messageID: string, reactionType: string, user_id?: string) {\n this._checkInitialized();\n if (!reactionType || !messageID) {\n throw Error(\n 'Deleting a reaction requires specifying both the message and reaction type',\n );\n }\n\n try {\n const offlineDb = this.getClient().offlineDb;\n if (offlineDb) {\n const message = this.state.messages.find(({ id }) => id === messageID);\n const reaction = {\n created_at: '',\n updated_at: '',\n message_id: messageID,\n type: reactionType,\n user_id: (this.getClient().userID as string) ?? user_id,\n };\n\n if (message) {\n await offlineDb.deleteReaction({\n message,\n reaction,\n });\n }\n\n return await offlineDb.queueTask<ReactionAPIResponse>({\n task: {\n channelId: this.id as string,\n channelType: this.type,\n messageId: messageID,\n payload: [messageID, reactionType],\n type: 'delete-reaction',\n },\n });\n }\n } catch (error) {\n this._client.logger('error', `offlineDb:delete-reaction`, {\n tags: ['channel', 'offlineDb'],\n error,\n });\n }\n\n return await this._deleteReaction(messageID, reactionType, user_id);\n }\n\n /**\n * deleteReaction - Delete a reaction by user and type\n *\n * @param {string} messageID the id of the message from which te remove the reaction\n * @param {string} reactionType the type of reaction that should be removed\n * @param {string} [user_id] the id of the user (used only for server side request) default null\n *\n * @return {Promise<ReactionAPIResponse>} The Server Response\n */\n async _deleteReaction(messageID: string, reactionType: string, user_id?: string) {\n this._checkInitialized();\n if (!reactionType || !messageID) {\n throw Error(\n 'Deleting a reaction requires specifying both the message and reaction type',\n );\n }\n\n const url =\n this.getClient().baseURL +\n `/messages/${encodeURIComponent(messageID)}/reaction/${encodeURIComponent(\n reactionType,\n )}`;\n //provided when server side request\n if (user_id) {\n return await this.getClient().delete<ReactionAPIResponse>(url, { user_id });\n }\n\n return await this.getClient().delete<ReactionAPIResponse>(url, {});\n }\n\n /**\n * update - Edit the channel's custom properties\n *\n * @param {ChannelData} channelData The object to update the custom properties of this channel with\n * @param {Message} [updateMessage] Optional message object for channel members notification\n * @param {ChannelUpdateOptions} [options] Option object, configuration to control the behavior while updating\n * @return {Promise<UpdateChannelAPIResponse>} The server response\n */\n async update(\n channelData: Partial<ChannelData & ChannelResponse> = {},\n updateMessage?: Message,\n options?: ChannelUpdateOptions,\n ) {\n // Strip out reserved names that will result in API errors.\n // TODO: this needs to be typed better\n const reserved: Exclude<\n keyof (ChannelResponse & ChannelData),\n keyof CustomChannelData\n >[] = [\n 'config',\n 'cid',\n 'created_by',\n 'id',\n 'member_count',\n 'type',\n 'created_at',\n 'updated_at',\n 'last_message_at',\n 'own_capabilities',\n ];\n\n reserved.forEach((key) => {\n delete channelData[key];\n });\n\n return await this._update({\n message: updateMessage,\n data: channelData,\n ...options,\n });\n }\n\n /**\n * updatePartial - partial update channel properties\n *\n * @param {PartialUpdateChannel} partial update request\n *\n * @return {Promise<PartialUpdateChannelAPIResponse>}\n */\n async updatePartial(update: PartialUpdateChannel) {\n const data = await this.getClient().patch<PartialUpdateChannelAPIResponse>(\n this._channelURL(),\n update,\n );\n\n const areCapabilitiesChanged =\n [...(data.channel.own_capabilities || [])].sort().join() !==\n [\n ...(Array.isArray(this.data?.own_capabilities)\n ? (this.data?.own_capabilities as string[])\n : []),\n ]\n .sort()\n .join();\n this.data = data.channel;\n // If the capabiltities are changed, we trigger the `capabilities.changed` event.\n if (areCapabilitiesChanged) {\n this.getClient().dispatchEvent({\n type: 'capabilities.changed',\n cid: this.cid,\n own_capabilities: data.channel.own_capabilities,\n });\n }\n return data;\n }\n\n /**\n * enableSlowMode - enable slow mode\n *\n * @param {number} coolDownInterval the cooldown interval in seconds\n * @return {Promise<UpdateChannelAPIResponse>} The server response\n */\n async enableSlowMode(coolDownInterval: number) {\n const data = await this.getClient().post<UpdateChannelAPIResponse>(\n this._channelURL(),\n {\n cooldown: coolDownInterval,\n },\n );\n this.data = data.channel;\n return data;\n }\n\n /**\n * disableSlowMode - disable slow mode\n *\n * @return {Promise<UpdateChannelAPIResponse>} The server response\n */\n async disableSlowMode() {\n const data = await this.getClient().post<UpdateChannelAPIResponse>(\n this._channelURL(),\n {\n cooldown: 0,\n },\n );\n this.data = data.channel;\n return data;\n }\n\n public async sendSharedLocation(\n location: StaticLocationPayload | LiveLocationPayload,\n userId?: string,\n ) {\n const result = await this.sendMessage({\n id: location.message_id,\n shared_location: location,\n user: userId ? { id: userId } : undefined,\n });\n\n if ((location as LiveLocationPayload).end_at) {\n this.getClient().dispatchEvent({\n message: result.message,\n type: 'live_location_sharing.started',\n });\n }\n\n return result;\n }\n\n public async stopLiveLocationSharing(payload: UpdateLocationPayload) {\n const location = await this.getClient().updateLocation({\n ...payload,\n end_at: new Date().toISOString(),\n });\n this.getClient().dispatchEvent({\n live_location: location,\n type: 'live_location_sharing.stopped',\n });\n }\n\n /**\n * delete - Delete the channel. Messages are permanently removed.\n *\n * @param {boolean} [options.hard_delete] Defines if the channel is hard deleted or not\n *\n * @return {Promise<DeleteChannelAPIResponse>} The server response\n */\n async delete(options: { hard_delete?: boolean } = {}) {\n return await this.getClient().delete<DeleteChannelAPIResponse>(this._channelURL(), {\n ...options,\n });\n }\n\n /**\n * truncate - Removes all messages from the channel\n * @param {TruncateOptions} [options] Defines truncation options\n * @return {Promise<TruncateChannelAPIResponse>} The server response\n */\n async truncate(options: TruncateOptions = {}) {\n return await this.getClient().post<TruncateChannelAPIResponse>(\n this._channelURL() + '/truncate',\n options,\n );\n }\n\n /**\n * acceptInvite - accept invitation to the channel\n *\n * @param {UpdateChannelOptions} [options] The object to update the custom properties of this channel with\n *\n * @return {Promise<UpdateChannelAPIResponse>} The server response\n */\n async acceptInvite(options: UpdateChannelOptions = {}) {\n return await this._update({ accept_invite: true, ...options });\n }\n\n /**\n * rejectInvite - reject invitation to the channel\n *\n * @param {UpdateChannelOptions} [options] The object to update the custom properties of this channel with\n *\n * @return {Promise<UpdateChannelAPIResponse>} The server response\n */\n async rejectInvite(options: UpdateChannelOptions = {}) {\n return await this._update({ reject_invite: true, ...options });\n }\n\n /**\n * addMembers - add members to the channel\n *\n * @param {string[] | Array<NewMemberPayload>} members An array of members to add to the channel\n * @param {Message} [message] Optional message object for channel members notification\n * @param {ChannelUpdateOptions} [options] Option object, configuration to control the behavior while updating\n * @return {Promise<UpdateChannelAPIResponse>} The server response\n */\n async addMembers(\n members: string[] | Array<NewMemberPayload>,\n message?: Message,\n options: ChannelUpdateOptions = {},\n ) {\n return await this._update({ add_members: members, message, ...options });\n }\n\n /**\n * addModerators - add moderators to the channel\n *\n * @param {string[]} members An array of member identifiers\n * @param {Message} [message] Optional message object for channel members notification\n * @param {ChannelUpdateOptions} [options] Option object, configuration to control the behavior while updating\n * @return {Promise<UpdateChannelAPIResponse>} The server response\n */\n async addModerators(\n members: string[],\n message?: Message,\n options: ChannelUpdateOptions = {},\n ) {\n return await this._update({ add_moderators: members, message, ...options });\n }\n\n /**\n * assignRoles - sets member roles in a channel\n *\n * @param {{channel_role: Role, user_id: string}[]} roles List of role assignments\n * @param {Message} [message] Optional message object for channel members notification\n * @param {ChannelUpdateOptions} [options] Option object, configuration to control the behavior while updating\n * @return {Promise<UpdateChannelAPIResponse>} The server response\n */\n async assignRoles(\n roles: { channel_role: Role; user_id: string }[],\n message?: Message,\n options: ChannelUpdateOptions = {},\n ) {\n return await this._update({ assign_roles: roles, message, ...options });\n }\n\n /**\n * inviteMembers - invite members to the channel\n *\n * @param {string[] | Array<NewMemberPayload>} members An array of members to invite to the channel\n * @param {Message} [message] Optional message object for channel members notification\n * @param {ChannelUpdateOptions} [options] Option object, configuration to control the behavior while updating\n * @return {Promise<UpdateChannelAPIResponse>} The server response\n */\n async inviteMembers(\n members: string[] | Required<Omit<NewMemberPayload, 'channel_role'>>[],\n message?: Message,\n options: ChannelUpdateOptions = {},\n ) {\n return await this._update({ invites: members, message, ...options });\n }\n\n /**\n * removeMembers - remove members from channel\n *\n * @param {string[]} members An array of member identifiers\n * @param {Message} [message] Optional message object for channel members notification\n * @param {ChannelUpdateOptions} [options] Option object, configuration to control the behavior while updating\n * @return {Promise<UpdateChannelAPIResponse>} The server response\n */\n async removeMembers(\n members: string[],\n message?: Message,\n options: ChannelUpdateOptions = {},\n ) {\n return await this._update({ remove_members: members, message, ...options });\n }\n\n /**\n * demoteModerators - remove moderator role from channel members\n *\n * @param {string[]} members An array of member identifiers\n * @param {Message} [message] Optional message object for channel members notification\n * @param {ChannelUpdateOptions} [options] Option object, configuration to control the behavior while updating\n * @return {Promise<UpdateChannelAPIResponse>} The server response\n */\n async demoteModerators(\n members: string[],\n message?: Message,\n options: ChannelUpdateOptions = {},\n ) {\n return await this._update({ demote_moderators: members, message, ...options });\n }\n\n /**\n * _update - executes channel update request\n * @param payload Object Update Channel payload\n * @return {Promise<UpdateChannelAPIResponse>} The server response\n * TODO: introduce new type instead of Object in the next major update\n */\n async _update(payload: object) {\n const data = await this.getClient().post<UpdateChannelAPIResponse>(\n this._channelURL(),\n payload,\n );\n this.data = data.channel;\n return data;\n }\n\n /**\n * mute - mutes the current channel\n * @param {{ user_id?: string, expiration?: string }} opts expiration in minutes or user_id\n * @return {Promise<MuteChannelAPIResponse>} The server response\n *\n * example with expiration:\n * await channel.mute({expiration: moment.duration(2, 'weeks')});\n *\n * example server side:\n * await channel.mute({user_id: userId});\n *\n */\n async mute(opts: { expiration?: number; user_id?: string } = {}) {\n return await this.getClient().post<MuteChannelAPIResponse>(\n this.getClient().baseURL + '/moderation/mute/channel',\n {\n channel_cid: this.cid,\n ...opts,\n },\n );\n }\n\n /**\n * unmute - mutes the current channel\n * @param {{ user_id?: string}} opts user_id\n * @return {Promise<APIResponse>} The server response\n *\n * example server side:\n * await channel.unmute({user_id: userId});\n */\n async unmute(opts: { user_id?: string } = {}) {\n return await this.getClient().post<APIResponse>(\n this.getClient().baseURL + '/moderation/unmute/channel',\n {\n channel_cid: this.cid,\n ...opts,\n },\n );\n }\n\n /**\n * archive - archives the current channel\n * @param {{ user_id?: string }} opts user_id if called server side\n * @return {Promise<ChannelMemberResponse>} The server response\n *\n * example:\n * await channel.archives();\n *\n * example server side:\n * await channel.archive({user_id: userId});\n *\n */\n async archive(opts: { user_id?: string } = {}) {\n const cli = this.getClient();\n const uid = opts.user_id || cli.userID;\n if (!uid) {\n throw Error('A user_id is required for archiving a channel');\n }\n const resp = await this.partialUpdateMember(uid, { set: { archived: true } });\n return resp.channel_member;\n }\n\n /**\n * unarchive - unarchives the current channel\n * @param {{ user_id?: string }} opts user_id if called server side\n * @return {Promise<ChannelMemberResponse>} The server response\n *\n * example:\n * await channel.unarchive();\n *\n * example server side:\n * await channel.unarchive({user_id: userId});\n *\n */\n async unarchive(opts: { user_id?: string } = {}) {\n const cli = this.getClient();\n const uid = opts.user_id || cli.userID;\n if (!uid) {\n throw Error('A user_id is required for unarchiving a channel');\n }\n const resp = await this.partialUpdateMember(uid, { set: { archived: false } });\n return resp.channel_member;\n }\n\n /**\n * pin - pins the current channel\n * @param {{ user_id?: string }} opts user_id if called server side\n * @return {Promise<ChannelMemberResponse>} The server response\n *\n * example:\n * await channel.pin();\n *\n * example server side:\n * await channel.pin({user_id: userId});\n *\n */\n async pin(opts: { user_id?: string } = {}) {\n const cli = this.getClient();\n const uid = opts.user_id || cli.userID;\n if (!uid) {\n throw new Error('A user_id is required for pinning a channel');\n }\n const resp = await this.partialUpdateMember(uid, { set: { pinned: true } });\n return resp.channel_member;\n }\n\n /**\n * unpin - unpins the current channel\n * @param {{ user_id?: string }} opts user_id if called server side\n * @return {Promise<ChannelMemberResponse>} The server response\n *\n * example:\n * await channel.unpin();\n *\n * example server side:\n * await channel.unpin({user_id: userId});\n *\n */\n async unpin(opts: { user_id?: string } = {}) {\n const cli = this.getClient();\n const uid = opts.user_id || cli.userID;\n if (!uid) {\n throw new Error('A user_id is required for unpinning a channel');\n }\n const resp = await this.partialUpdateMember(uid, { set: { pinned: false } });\n return resp.channel_member;\n }\n\n /**\n * muteStatus - returns the mute status for the current channel\n * @return {{ muted: boolean; createdAt: Date | null; expiresAt: Date | null }} { muted: true | false, createdAt: Date | null, expiresAt: Date | null}\n */\n muteStatus(): {\n createdAt: Date | null;\n expiresAt: Date | null;\n muted: boolean;\n } {\n this._checkInitialized();\n return this.getClient()._muteStatus(this.cid);\n }\n\n sendAction(messageID: string, formData: Record<string, string>) {\n this._checkInitialized();\n if (!messageID) {\n throw Error(`Message id is missing`);\n }\n return this.getClient().post<SendMessageAPIResponse>(\n this.getClient().baseURL + `/messages/${encodeURIComponent(messageID)}/action`,\n {\n message_id: messageID,\n form_data: formData,\n id: this.id,\n type: this.type,\n },\n );\n }\n\n /**\n * keystroke - First of the typing.start and typing.stop events based on the users keystrokes.\n * Call this on every keystroke\n * @see {@link https://getstream.io/chat/docs/typing_indicators/?language=js|Docs}\n * @param {string} [parent_id] set this field to `message.id` to indicate that typing event is happening in a thread\n */\n async keystroke(parent_id?: string, options?: { user_id: string }) {\n if (!this._isTypingIndicatorsEnabled()) {\n return;\n }\n const now = new Date();\n const diff = this.lastTypingEvent && now.getTime() - this.lastTypingEvent.getTime();\n this.lastKeyStroke = now;\n this.isTyping = true;\n // send a typing.start every 2 seconds\n if (diff === null || diff > 2000) {\n this.lastTypingEvent = new Date();\n await this.sendEvent({\n type: 'typing.start',\n parent_id,\n ...(options || {}),\n } as Event);\n }\n }\n\n /**\n * Sends an event to update the AI state for a specific message.\n * Typically used by the server connected to the AI service to notify clients of state changes.\n *\n * @param messageId - The ID of the message associated with the AI state.\n * @param state - The new state of the AI process (e.g., thinking, generating).\n * @param options - Optional parameters, such as `ai_message`, to include additional details in the event.\n */\n async updateAIState(\n messageId: string,\n state: AIState,\n options: { ai_message?: string } = {},\n ) {\n await this.sendEvent({\n ...options,\n type: 'ai_indicator.update',\n message_id: messageId,\n ai_state: state,\n } as Event);\n }\n\n /**\n * Sends an event to notify watchers to clear the typing/thinking UI when the AI response starts streaming.\n * Typically used by the server connected to the AI service to inform clients that the AI response has started.\n */\n async clearAIIndicator() {\n await this.sendEvent({\n type: 'ai_indicator.clear',\n } as Event);\n }\n\n /**\n * Sends an event to stop AI response generation, leaving the message in its current state.\n * Triggered by the user to halt the AI response process.\n */\n async stopAIResponse() {\n await this.sendEvent({\n type: 'ai_indicator.stop',\n } as Event);\n }\n\n /**\n * stopTyping - Sets last typing to null and sends the typing.stop event\n * @see {@link https://getstream.io/chat/docs/typing_indicators/?language=js|Docs}\n * @param {string} [parent_id] set this field to `message.id` to indicate that typing event is happening in a thread\n */\n async stopTyping(parent_id?: string, options?: { user_id: string }) {\n if (!this._isTypingIndicatorsEnabled()) {\n return;\n }\n this.lastTypingEvent = null;\n this.isTyping = false;\n await this.sendEvent({\n type: 'typing.stop',\n parent_id,\n ...(options || {}),\n } as Event);\n }\n\n _isTypingIndicatorsEnabled(): boolean {\n if (!this.getConfig()?.typing_events || !this.getClient().wsConnection?.isHealthy) {\n return false;\n }\n return this.getClient().user?.privacy_settings?.typing_indicators?.enabled ?? true;\n }\n\n /**\n * lastMessage - return the last message, takes into account that last few messages might not be perfectly sorted\n *\n * @return {ReturnType<ChannelState['formatMessage']> | undefined} Description\n */\n lastMessage(): LocalMessage | undefined {\n // get last 5 messages, sort, return the latest\n // get a slice of the last 5\n let min = this.state.latestMessages.length - 5;\n if (min < 0) {\n min = 0;\n }\n const max = this.state.latestMessages.length + 1;\n const messageSlice = this.state.latestMessages.slice(min, max);\n\n // sort by pk desc\n messageSlice.sort((a, b) => b.created_at.getTime() - a.created_at.getTime());\n\n return messageSlice[0];\n }\n\n /**\n * markRead - Send the mark read event for this user, only works if the `read_events` setting is enabled\n *\n * @param {MarkReadOptions} data\n * @return {Promise<EventAPIResponse | null>} Description\n */\n async markRead(data: MarkReadOptions = {}) {\n this._checkInitialized();\n\n if (!this.getConfig()?.read_events && !this.getClient()._isUsingServerAuth()) {\n return Promise.resolve(null);\n }\n\n return await this.getClient().post<EventAPIResponse>(this._channelURL() + '/read', {\n ...data,\n });\n }\n\n /**\n * markUnread - Mark the channel as unread from messageID, only works if the `read_events` setting is enabled\n *\n * @param {MarkUnreadOptions} data\n * @return {APIResponse} An API response\n */\n async markUnread(data: MarkUnreadOptions) {\n this._checkInitialized();\n\n if (!this.getConfig()?.read_events && !this.getClient()._isUsingServerAuth()) {\n return Promise.resolve(null);\n }\n\n return await this.getClient().post<APIResponse>(this._channelURL() + '/unread', {\n ...data,\n });\n }\n\n /**\n * clean - Cleans the channel state and fires stop typing if needed\n */\n clean() {\n if (this.lastKeyStroke) {\n const now = new Date();\n const diff = now.getTime() - this.lastKeyStroke.getTime();\n if (diff > 1000 && this.isTyping) {\n logChatPromiseExecution(this.stopTyping(), 'stop typing event');\n }\n }\n\n this.state.clean();\n }\n\n /**\n * watch - Loads the initial channel state and watches for changes\n *\n * @param {ChannelQueryOptions} options additional options for the query endpoint\n *\n * @return {Promise<QueryChannelAPIResponse>} The server response\n */\n async watch(options?: ChannelQueryOptions) {\n const defaultOptions = {\n state: true,\n watch: true,\n presence: false,\n };\n\n // Make sure we wait for the connect promise if there is a pending one\n await this.getClient().wsPromise;\n\n if (!this.getClient()._hasConnectionID()) {\n defaultOptions.watch = false;\n }\n\n const combined = { ...defaultOptions, ...options };\n const state = await this.query(combined, 'latest');\n this.initialized = true;\n this.data = state.channel;\n\n this._client.logger(\n 'info',\n `channel:watch() - started watching channel ${this.cid}`,\n {\n tags: ['channel'],\n channel: this,\n },\n );\n return state;\n }\n\n /**\n * stopWatching - Stops watching the channel\n *\n * @return {Promise<APIResponse>} The server response\n */\n async stopWatching() {\n const response = await this.getClient().post<APIResponse>(\n this._channelURL() + '/stop-watching',\n {},\n );\n\n this._client.logger(\n 'info',\n `channel:watch() - stopped watching channel ${this.cid}`,\n {\n tags: ['channel'],\n channel: this,\n },\n );\n\n return response;\n }\n\n /**\n * getReplies - List the message replies for a parent message.\n *\n * The recommended way of working with threads is to use the Thread class.\n *\n * @param {string} parent_id The message parent id, ie the top of the thread\n * @param {MessagePaginationOptions & { user?: UserResponse; user_id?: string }} options Pagination params, ie {limit:10, id_lte: 10}\n *\n * @return {Promise<GetRepliesAPIResponse>} A response with a list of messages\n */\n async getReplies(\n parent_id: string,\n options: MessagePaginationOptions & { user?: UserResponse; user_id?: string },\n sort?: { created_at: AscDesc }[],\n ) {\n const normalizedSort = sort ? normalizeQuerySort(sort) : undefined;\n const data = await this.getClient().get<GetRepliesAPIResponse>(\n this.getClient().baseURL + `/messages/${encodeURIComponent(parent_id)}/replies`,\n {\n sort: normalizedSort,\n ...options,\n },\n );\n\n // add any messages to our thread state\n if (data.messages) {\n this.state.addMessagesSorted(data.messages);\n }\n\n return data;\n }\n\n /**\n * getPinnedMessages - List list pinned messages of the channel\n *\n * @param {PinnedMessagePaginationOptions & { user?: UserResponse; user_id?: string }} options Pagination params, ie {limit:10, id_lte: 10}\n * @param {PinnedMessagesSort} sort defines sorting direction of pinned messages\n *\n * @return {Promise<GetRepliesAPIResponse>} A response with a list of messages\n */\n async getPinnedMessages(\n options: PinnedMessagePaginationOptions & { user?: UserResponse; user_id?: string },\n sort: PinnedMessagesSort = [],\n ) {\n return await this.getClient().get<GetRepliesAPIResponse>(\n this._channelURL() + '/pinned_messages',\n {\n payload: {\n ...options,\n sort: normalizeQuerySort(sort),\n },\n },\n );\n }\n\n /**\n * getReactions - List the reactions, supports pagination\n *\n * @param {string} message_id The message id\n * @param {{ limit?: number; offset?: number }} options The pagination options\n *\n * @return {Promise<GetReactionsAPIResponse>} Server response\n */\n getReactions(message_id: string, options: { limit?: number; offset?: number }) {\n return this.getClient().get<GetReactionsAPIResponse>(\n this.getClient().baseURL + `/messages/${encodeURIComponent(message_id)}/reactions`,\n {\n ...options,\n },\n );\n }\n\n /**\n * getMessagesById - Retrieves a list of messages by ID\n *\n * @param {string[]} messageIds The ids of the messages to retrieve from this channel\n *\n * @return {Promise<GetMultipleMessagesAPIResponse>} Server response\n */\n getMessagesById(messageIds: string[]) {\n return this.getClient().get<GetMultipleMessagesAPIResponse>(\n this._channelURL() + '/messages',\n {\n ids: messageIds.join(','),\n },\n );\n }\n\n /**\n * lastRead - returns the last time the user marked the channel as read if the user never marked the channel as read, this will return null\n * @return {Date | null | undefined}\n */\n lastRead() {\n const { userID } = this.getClient();\n if (userID) {\n return this.state.read[userID] ? this.state.read[userID].last_read : null;\n }\n }\n\n _countMessageAsUnread(message: LocalMessage | MessageResponse) {\n if (message.shadowed) return false;\n if (message.silent) return false;\n if (message.parent_id && !message.show_in_channel) return false;\n if (message.user?.id === this.getClient().userID) return false;\n if (message.user?.id && this.getClient().userMuteStatus(message.user.id))\n return false;\n\n // Return false if channel doesn't allow read events.\n if (\n Array.isArray(this.data?.own_capabilities) &&\n !this.data?.own_capabilities.includes('read-events')\n ) {\n return false;\n }\n\n // FIXME: see #1265, adjust and count new messages even when the channel is muted\n if (this.muteStatus().muted) return false;\n\n return true;\n }\n\n /**\n * countUnread - Count of unread messages\n *\n * @param {Date | null} [lastRead] lastRead the time that the user read a message, defaults to current user's read state\n *\n * @return {number} Unread count\n */\n countUnread(lastRead?: Date | null) {\n if (!lastRead) return this.state.unreadCount;\n // todo: prevent finding the latest message set on each iteration\n let count = 0;\n for (let i = 0; i < this.state.latestMessages.length; i += 1) {\n const message = this.state.latestMessages[i];\n if (message.created_at > lastRead && this._countMessageAsUnread(message)) {\n count++;\n }\n }\n return count;\n }\n\n /**\n * countUnreadMentions - Count the number of unread messages mentioning the current user\n *\n * @return {number} Unread mentions count\n */\n countUnreadMentions() {\n const lastRead = this.lastRead();\n const userID = this.getClient().userID;\n\n let count = 0;\n for (let i = 0; i < this.state.latestMessages.length; i += 1) {\n const message = this.state.latestMessages[i];\n if (\n this._countMessageAsUnread(message) &&\n (!lastRead || message.created_at > lastRead) &&\n message.mentioned_users?.some((user) => user.id === userID)\n ) {\n count++;\n }\n }\n return count;\n }\n\n /**\n * create - Creates a new channel\n *\n * @return {Promise<QueryChannelAPIResponse>} The Server Response\n *\n */\n create = async (options?: ChannelQueryOptions) => {\n const defaultOptions = {\n ...options,\n watch: false,\n state: false,\n presence: false,\n };\n return await this.query(defaultOptions, 'latest');\n };\n\n /**\n * query - Query the API, get messages, members or other channel fields\n *\n * @param {ChannelQueryOptions} options The query options\n * @param {MessageSetType} messageSetToAddToIfDoesNotExist It's possible to load disjunct sets of a channel's messages into state, use `current` to load the initial channel state or if you want to extend the currently displayed messages, use `latest` if you want to load/extend the latest messages, `new` is used for loading a specific message and it's surroundings\n *\n * @return {Promise<QueryChannelAPIResponse>} Returns a query response\n */\n async query(\n options: ChannelQueryOptions = {},\n messageSetToAddToIfDoesNotExist: MessageSetType = 'current',\n ) {\n // Make sure we wait for the connect promise if there is a pending one\n await this.getClient().wsPromise;\n\n const createdById =\n options.created_by?.id ??\n options.created_by_id ??\n this._data?.created_by?.id ??\n this._data?.created_by_id;\n\n if (this.getClient()._isUsingServerAuth() && typeof createdById !== 'string') {\n this.getClient().logger(\n 'warn',\n 'Either `created_by` (with `id` property) or `created_by_id` are missing from both `Channel._data` and `options` parameter',\n );\n }\n\n let queryURL = `${this.getClient().baseURL}/channels/${encodeURIComponent(\n this.type,\n )}`;\n if (this.id) {\n queryURL += `/${encodeURIComponent(this.id)}`;\n }\n\n const state = await this.getClient().post<QueryChannelAPIResponse>(\n queryURL + '/query',\n {\n data: this._data,\n state: true,\n ...options,\n },\n );\n\n // update the channel id if it was missing\n if (!this.id) {\n this.id = state.channel.id;\n this.cid = state.channel.cid;\n // set the channel as active...\n\n const tempChannelCid = generateChannelTempCid(\n this.type,\n state.members.map((member) => member.user_id || member.user?.id || ''),\n );\n\n if (tempChannelCid && tempChannelCid in this.getClient().activeChannels) {\n // This gets set in `client.channel()` function, when channel is created\n // using members, not id.\n delete this.getClient().activeChannels[tempChannelCid];\n }\n\n if (\n !(this.cid in this.getClient().activeChannels) &&\n this.getClient()._cacheEnabled()\n ) {\n this.getClient().activeChannels[this.cid] = this;\n }\n }\n\n this.getClient()._addChannelConfig(state.channel);\n\n // the only config param that is necessary to be updated based on server config soon as the config is delivered\n if (typeof state.channel.config?.shared_locations !== 'undefined') {\n this.messageComposer.updateConfig({\n location: { enabled: state.channel.config.shared_locations },\n });\n }\n\n // add any messages to our channel state\n const { messageSet } = this._initializeState(state, messageSetToAddToIfDoesNotExist);\n messageSet.pagination = {\n ...messageSet.pagination,\n ...messageSetPagination({\n parentSet: messageSet,\n messagePaginationOptions: options?.messages,\n requestedPageSize:\n options?.messages?.limit ?? DEFAULT_QUERY_CHANNEL_MESSAGE_LIST_PAGE_SIZE,\n returnedPage: state.messages,\n logger: this.getClient().logger,\n }),\n };\n\n this.getClient().polls.hydratePollCache(state.messages, true);\n this.getClient().reminders.hydrateState(state.messages);\n\n this.messageComposer.initStateFromChannelResponse(state);\n\n const areCapabilitiesChanged =\n [...(state.channel.own_capabilities || [])].sort().join() !==\n [\n ...(this.data && Array.isArray(this.data?.own_capabilities)\n ? this.data.own_capabilities\n : []),\n ]\n .sort()\n .join();\n this.data = state.channel;\n this.offlineMode = false;\n\n if (areCapabilitiesChanged) {\n this.getClient().dispatchEvent({\n type: 'capabilities.changed',\n cid: this.cid,\n own_capabilities: state.channel.own_capabilities,\n });\n }\n\n this.getClient().dispatchEvent({\n type: 'channels.queried',\n queriedChannels: {\n channels: [state],\n isLatestMessageSet: messageSet.isLatest,\n },\n });\n this.getClient().offlineDb?.executeQuerySafely(\n (db) =>\n db.upsertChannels?.({\n channels: [state],\n isLatestMessagesSet: messageSet.isLatest,\n }),\n { method: 'upsertChannels' },\n );\n\n return state;\n }\n\n /**\n * banUser - Bans a user from a channel\n *\n * @param {string} targetUserID\n * @param {BanUserOptions} options\n * @returns {Promise<APIResponse>}\n */\n async banUser(targetUserID: string, options: BanUserOptions) {\n this._checkInitialized();\n return await this.getClient().banUser(targetUserID, {\n ...options,\n type: this.type,\n id: this.id,\n });\n }\n\n /**\n * hides the channel from queryChannels for the user until a message is added\n * If clearHistory is set to true - all messages will be removed for the user\n *\n * @param {string | null} userId\n * @param {boolean} clearHistory\n * @returns {Promise<APIResponse>}\n */\n async hide(userId: string | null = null, clearHistory = false) {\n this._checkInitialized();\n\n return await this.getClient().post<APIResponse>(`${this._channelURL()}/hide`, {\n user_id: userId,\n clear_history: clearHistory,\n });\n }\n\n /**\n * removes the hidden status for a channel\n *\n * @param {string | null} userId\n * @returns {Promise<APIResponse>}\n */\n async show(userId: string | null = null) {\n this._checkInitialized();\n return await this.getClient().post<APIResponse>(`${this._channelURL()}/show`, {\n user_id: userId,\n });\n }\n\n /**\n * unbanUser - Removes the bans for a user on a channel\n *\n * @param {string} targetUserID\n * @returns {Promise<APIResponse>}\n */\n async unbanUser(targetUserID: string) {\n this._checkInitialized();\n return await this.getClient().unbanUser(targetUserID, {\n type: this.type,\n id: this.id,\n });\n }\n\n /**\n * shadowBan - Shadow bans a user from a channel\n *\n * @param {string} targetUserID\n * @param {BanUserOptions} options\n * @returns {Promise<APIResponse>}\n */\n async shadowBan(targetUserID: string, options: BanUserOptions) {\n this._checkInitialized();\n return await this.getClient().shadowBan(targetUserID, {\n ...options,\n type: this.type,\n id: this.id,\n });\n }\n\n /**\n * removeShadowBan - Removes the shadow ban for a user on a channel\n *\n * @param {string} targetUserID\n * @returns {Promise<APIResponse>}\n */\n async removeShadowBan(targetUserID: string) {\n this._checkInitialized();\n return await this.getClient().removeShadowBan(targetUserID, {\n type: this.type,\n id: this.id,\n });\n }\n\n /**\n * Cast or cancel one or more votes on a poll\n * @param pollId string The poll id\n * @param votes PollVoteData[] The votes that will be casted (or canceled in case of an empty array)\n * @returns {APIResponse & PollVoteResponse} The poll votes\n */\n async vote(messageId: string, pollId: string, vote: PollVoteData) {\n return await this.getClient().castPollVote(messageId, pollId, vote);\n }\n\n async removeVote(messageId: string, pollId: string, voteId: string) {\n return await this.getClient().removePollVote(messageId, pollId, voteId);\n }\n\n /**\n * createDraft - Creates or updates a draft message in a channel\n *\n * @param {DraftMessagePayload} message The draft message to create or update\n *\n * @return {Promise<CreateDraftResponse>} Response containing the created draft\n */\n async _createDraft(message: DraftMessagePayload) {\n return await this.getClient().post<CreateDraftResponse>(\n this._channelURL() + '/draft',\n {\n message,\n },\n );\n }\n\n /**\n * createDraft - Creates or updates a draft message in a channel. If offline support is\n * enabled, it will make sure that creating the draft is queued up if it fails due to\n * bad internet conditions and executed later.\n *\n * @param {DraftMessagePayload} message The draft message to create or update\n *\n * @return {Promise<CreateDraftResponse>} Response containing the created draft\n */\n async createDraft(message: DraftMessagePayload) {\n try {\n const offlineDb = this.getClient().offlineDb;\n if (offlineDb) {\n return await offlineDb.queueTask<CreateDraftResponse>({\n task: {\n channelId: this.id as string,\n channelType: this.type,\n threadId: message.parent_id,\n payload: [message],\n type: 'create-draft',\n },\n });\n }\n } catch (error) {\n this._client.logger('error', `offlineDb:create-draft`, {\n tags: ['channel', 'offlineDb'],\n error,\n });\n }\n\n return this._createDraft(message);\n }\n\n /**\n * deleteDraft - Deletes a draft message from a channel or a thread.\n *\n * @param {Object} options\n * @param {string} options.parent_id Optional parent message ID for drafts in threads\n *\n * @return {Promise<APIResponse>} API response\n */\n async _deleteDraft({ parent_id }: { parent_id?: string } = {}) {\n return await this.getClient().delete<APIResponse>(this._channelURL() + '/draft', {\n parent_id,\n });\n }\n\n /**\n * deleteDraft - Deletes a draft message from a channel or a thread. If offline support is\n * enabled, it will make sure that deleting the draft is queued up if it fails due to\n * bad internet conditions and executed later.\n *\n * @param {Object} options\n * @param {string} options.parent_id Optional parent message ID for drafts in threads\n *\n * @return {Promise<APIResponse>} API response\n */\n async deleteDraft(options: { parent_id?: string } = {}) {\n const { parent_id } = options;\n try {\n const offlineDb = this.getClient().offlineDb;\n if (offlineDb) {\n return await offlineDb.queueTask<APIResponse>({\n task: {\n channelId: this.id as string,\n channelType: this.type,\n threadId: parent_id,\n payload: [options],\n type: 'delete-draft',\n },\n });\n }\n } catch (error) {\n this._client.logger('error', `offlineDb:delete-draft`, {\n tags: ['channel', 'offlineDb'],\n error,\n });\n }\n\n return this._deleteDraft(options);\n }\n\n /**\n * getDraft - Retrieves a draft message from a channel\n *\n * @param {Object} options\n * @param {string} options.parent_id Optional parent message ID for drafts in threads\n *\n * @return {Promise<GetDraftResponse>} Response containing the draft\n */\n async getDraft({ parent_id }: { parent_id?: string } = {}) {\n return await this.getClient().get<GetDraftResponse>(this._channelURL() + '/draft', {\n parent_id,\n });\n }\n\n /**\n * on - Listen to events on this channel.\n *\n * channel.on('message.new', event => {console.log(\"my new message\", event, channel.state.messages)})\n * or\n * channel.on(event => {console.log(event.type)})\n *\n * @param {EventHandler | EventTypes} callbackOrString The event type to listen for (optional)\n * @param {EventHandler} [callbackOrNothing] The callback to call\n */\n on(eventType: EventTypes, callback: EventHandler): { unsubscribe: () => void };\n on(callback: EventHandler): { unsubscribe: () => void };\n on(\n callbackOrString: EventHandler | EventTypes,\n callbackOrNothing?: EventHandler,\n ): { unsubscribe: () => void } {\n const key = callbackOrNothing ? (callbackOrString as string) : 'all';\n const callback = callbackOrNothing ? callbackOrNothing : callbackOrString;\n if (!(key in this.listeners)) {\n this.listeners[key] = [];\n }\n this._client.logger(\n 'info',\n `Attaching listener for ${key} event on channel ${this.cid}`,\n {\n tags: ['event', 'channel'],\n channel: this,\n },\n );\n\n this.listeners[key].push(callback);\n\n return {\n unsubscribe: () => {\n this._client.logger(\n 'info',\n `Removing listener for ${key} event from channel ${this.cid}`,\n {\n tags: ['event', 'channel'],\n channel: this,\n },\n );\n\n this.listeners[key] = this.listeners[key].filter((el) => el !== callback);\n },\n };\n }\n\n /**\n * off - Remove the event handler\n *\n */\n off(eventType: EventTypes, callback: EventHandler): void;\n off(callback: EventHandler): void;\n off(\n callbackOrString: EventHandler | EventTypes,\n callbackOrNothing?: EventHandler,\n ): void {\n const key = callbackOrNothing ? (callbackOrString as string) : 'all';\n const callback = callbackOrNothing ? callbackOrNothing : callbackOrString;\n if (!(key in this.listeners)) {\n this.listeners[key] = [];\n }\n\n this._client.logger(\n 'info',\n `Removing listener for ${key} event from channel ${this.cid}`,\n {\n tags: ['event', 'channel'],\n channel: this,\n },\n );\n this.listeners[key] = this.listeners[key].filter((value) => value !== callback);\n }\n\n _handleChannelEvent(event: Event) {\n // eslint-disable-next-line @typescript-eslint/no-this-alias\n const channel = this;\n this._client.logger(\n 'info',\n `channel:_handleChannelEvent - Received event of type { ${event.type} } on ${this.cid}`,\n {\n tags: ['event', 'channel'],\n channel: this,\n },\n );\n\n const channelState = channel.state;\n switch (event.type) {\n case 'typing.start':\n if (event.user?.id) {\n channelState.typing[event.user.id] = event;\n }\n break;\n case 'typing.stop':\n if (event.user?.id) {\n delete channelState.typing[event.user.id];\n }\n break;\n case 'message.read':\n if (event.user?.id && event.created_at) {\n channelState.read[event.user.id] = {\n last_read: new Date(event.created_at),\n last_read_message_id: event.last_read_message_id,\n user: event.user,\n unread_messages: 0,\n };\n\n if (event.user?.id === this.getClient().user?.id) {\n channelState.unreadCount = 0;\n }\n }\n break;\n case 'user.watching.start':\n case 'user.updated':\n if (event.user?.id) {\n channelState.watchers[event.user.id] = event.user;\n }\n break;\n case 'user.watching.stop':\n if (event.user?.id) {\n delete channelState.watchers[event.user.id];\n }\n break;\n case 'message.deleted':\n if (event.message) {\n this._extendEventWithOwnReactions(event);\n if (event.hard_delete) channelState.removeMessage(event.message);\n else channelState.addMessageSorted(event.message, false, false);\n\n channelState.removeQuotedMessageReferences(event.message);\n\n if (event.message.pinned) {\n channelState.removePinnedMessage(event.message);\n }\n }\n break;\n case 'user.messages.deleted':\n if (event.user) {\n this.state.deleteUserMessages(\n event.user,\n !!event.hard_delete,\n new Date(event.created_at ?? Date.now()),\n );\n }\n break;\n case 'message.new':\n if (event.message) {\n /* if message belongs to current user, always assume timestamp is changed to filter it out and add again to avoid duplication */\n const ownMessage = event.user?.id === this.getClient().user?.id;\n const isThreadMessage =\n event.message.parent_id && !event.message.show_in_channel;\n\n if (this.state.isUpToDate || isThreadMessage) {\n channelState.addMessageSorted(event.message, ownMessage);\n }\n\n if (event.message.pinned) {\n channelState.addPinnedMessage(event.message);\n }\n\n // do not increase the unread count - the back-end does not increase the count neither in the following cases:\n // 1. the message is mine\n // 2. the message is a thread reply from any user\n const preventUnreadCountUpdate = ownMessage || isThreadMessage;\n if (preventUnreadCountUpdate) break;\n\n if (event.user?.id) {\n for (const userId in channelState.read) {\n if (userId === event.user.id) {\n channelState.read[event.user.id] = {\n last_read: new Date(event.created_at as string),\n user: event.user,\n unread_messages: 0,\n };\n } else {\n channelState.read[userId].unread_messages += 1;\n }\n }\n }\n\n if (this._countMessageAsUnread(event.message)) {\n channelState.unreadCount = channelState.unreadCount + 1;\n }\n }\n break;\n case 'message.updated':\n case 'message.undeleted':\n if (event.message) {\n this._extendEventWithOwnReactions(event);\n channelState.addMessageSorted(event.message, false, false);\n channelState._updateQuotedMessageReferences({ message: event.message });\n if (event.message.pinned) {\n channelState.addPinnedMessage(event.message);\n } else {\n channelState.removePinnedMessage(event.message);\n }\n }\n break;\n case 'channel.truncated':\n if (event.channel?.truncated_at) {\n const truncatedAt = +new Date(event.channel.truncated_at);\n\n channelState.messageSets.forEach((messageSet, messageSetIndex) => {\n messageSet.messages.forEach(({ created_at: createdAt, id }) => {\n if (truncatedAt > +createdAt)\n channelState.removeMessage({ id, messageSetIndex });\n });\n });\n\n channelState.pinnedMessages.forEach(({ id, created_at: createdAt }) => {\n if (truncatedAt > +createdAt)\n channelState.removePinnedMessage({ id } as MessageResponse);\n });\n channelState.unreadCount = this.countUnread(\n new Date(event.channel.truncated_at),\n );\n } else {\n channelState.clearMessages();\n channelState.unreadCount = 0;\n }\n\n // system messages don't increment unread counts\n if (event.message) {\n channelState.addMessageSorted(event.message);\n if (event.message.pinned) {\n channelState.addPinnedMessage(event.message);\n }\n }\n\n break;\n case 'member.added':\n case 'member.updated': {\n const memberCopy: ChannelMemberResponse = {\n ...event.member,\n };\n\n if (memberCopy.pinned_at === null) {\n delete memberCopy.pinned_at;\n }\n\n if (memberCopy.archived_at === null) {\n delete memberCopy.archived_at;\n }\n\n if (memberCopy?.user) {\n channelState.members = {\n ...channelState.members,\n [memberCopy.user.id]: memberCopy,\n };\n if (channel.data?.member_count && event.type === 'member.added') {\n channel.data.member_count += 1;\n }\n }\n\n const currentUserId = this.getClient().userID;\n if (\n typeof currentUserId === 'string' &&\n typeof memberCopy?.user?.id === 'string' &&\n memberCopy.user.id === currentUserId\n ) {\n channelState.membership = memberCopy;\n }\n break;\n }\n case 'member.removed':\n if (event.user?.id) {\n const newMembers = {\n ...channelState.members,\n };\n\n delete newMembers[event.user.id];\n\n channelState.members = newMembers;\n\n if (channel.data?.member_count) {\n channel.data.member_count = Math.max(channel.data.member_count - 1, 0);\n }\n\n // TODO?: unset membership\n }\n break;\n case 'notification.mark_unread': {\n const ownMessage = event.user?.id === this.getClient().user?.id;\n if (!(ownMessage && event.user)) break;\n\n const unreadCount = event.unread_messages ?? 0;\n\n channelState.read[event.user.id] = {\n first_unread_message_id: event.first_unread_message_id,\n last_read: new Date(event.last_read_at as string),\n last_read_message_id: event.last_read_message_id,\n user: event.user,\n unread_messages: unreadCount,\n };\n\n channelState.unreadCount = unreadCount;\n break;\n }\n case 'channel.updated':\n if (event.channel) {\n const isFrozenChanged =\n event.channel?.frozen !== undefined &&\n event.channel.frozen !== channel.data?.frozen;\n if (isFrozenChanged) {\n this.query({ state: false, messages: { limit: 0 }, watchers: { limit: 0 } });\n }\n const newChannelData = {\n ...event.channel,\n hidden: event.channel?.hidden ?? channel.data?.hidden,\n own_capabilities:\n event.channel?.own_capabilities ?? channel.data?.own_capabilities,\n };\n channel.data = newChannelData;\n }\n break;\n case 'reaction.new':\n if (event.message && event.reaction) {\n const { message, reaction } = event;\n event.message = channelState.addReaction(reaction, message) as MessageResponse;\n }\n break;\n case 'reaction.deleted':\n if (event.message && event.reaction) {\n const { message, reaction } = event;\n event.message = channelState.removeReaction(reaction, message);\n }\n break;\n case 'reaction.updated':\n if (event.message && event.reaction) {\n const { message, reaction } = event;\n // assuming reaction.updated is only called if enforce_unique is true\n event.message = channelState.addReaction(\n reaction,\n message,\n true,\n ) as MessageResponse;\n }\n break;\n case 'channel.hidden':\n channel.data = {\n ...channel.data,\n blocked: !!event.channel?.blocked,\n hidden: true,\n };\n if (event.clear_history) {\n channelState.clearMessages();\n }\n break;\n case 'channel.visible':\n channel.data = {\n ...channel.data,\n blocked: !!event.channel?.blocked,\n hidden: false,\n };\n this.getClient().offlineDb?.handleChannelVisibilityEvent({ event });\n break;\n case 'user.banned':\n if (!event.user?.id) break;\n channelState.members[event.user.id] = {\n ...(channelState.members[event.user.id] || {}),\n shadow_banned: !!event.shadow,\n banned: !event.shadow,\n user: { ...(channelState.members[event.user.id]?.user || {}), ...event.user },\n };\n break;\n case 'user.unbanned':\n if (!event.user?.id) break;\n channelState.members[event.user.id] = {\n ...(channelState.members[event.user.id] || {}),\n shadow_banned: false,\n banned: false,\n user: { ...(channelState.members[event.user.id]?.user || {}), ...event.user },\n };\n break;\n default:\n }\n\n // any event can send over the online count\n if (event.watcher_count !== undefined) {\n channel.state.watcher_count = event.watcher_count;\n }\n }\n\n _callChannelListeners = (event: Event) => {\n // eslint-disable-next-line @typescript-eslint/no-this-alias\n const channel = this;\n // gather and call the listeners\n const listeners = [];\n if (channel.listeners.all) {\n listeners.push(...channel.listeners.all);\n }\n if (channel.listeners[event.type]) {\n listeners.push(...channel.listeners[event.type]);\n }\n\n // call the event and send it to the listeners\n for (const listener of listeners) {\n if (typeof listener !== 'string') {\n listener(event);\n }\n }\n };\n\n /**\n * _channelURL - Returns the channel url\n *\n * @return {string} The channel url\n */\n _channelURL = () => {\n if (!this.id) {\n throw new Error('channel id is not defined');\n }\n return `${this.getClient().baseURL}/channels/${encodeURIComponent(\n this.type,\n )}/${encodeURIComponent(this.id)}`;\n };\n\n _checkInitialized() {\n if (\n !this.initialized &&\n !this.offlineMode &&\n !this.getClient()._isUsingServerAuth()\n ) {\n throw Error(\n `Channel ${this.cid} hasn't been initialized yet. Make sure to call .watch() and wait for it to resolve`,\n );\n }\n }\n\n _initializeState(\n state: ChannelAPIResponse,\n messageSetToAddToIfDoesNotExist: MessageSetType = 'latest',\n ) {\n const { state: clientState, user, userID } = this.getClient();\n\n // add the members and users\n if (state.members) {\n this._hydrateMembers({ members: state.members });\n\n for (const member of state.members) {\n if (member.user) {\n clientState.updateUserReference(member.user, this.cid);\n }\n }\n }\n\n this.state.membership = state.membership || {};\n\n const messages = state.messages || [];\n if (!this.state.messages) {\n this.state.initMessages();\n }\n const { messageSet } = this.state.addMessagesSorted(\n messages,\n false,\n true,\n true,\n messageSetToAddToIfDoesNotExist,\n );\n\n if (!this.state.pinnedMessages) {\n this.state.pinnedMessages = [];\n }\n this.state.addPinnedMessages(state.pinned_messages || []);\n if (state.pending_messages) {\n this.state.pending_messages = state.pending_messages;\n }\n if (state.watcher_count !== undefined) {\n this.state.watcher_count = state.watcher_count;\n }\n // convert the arrays into objects for easier syncing...\n if (state.watchers) {\n for (const watcher of state.watchers) {\n if (watcher) {\n clientState.updateUserReference(watcher, this.cid);\n this.state.watchers[watcher.id] = watcher;\n }\n }\n }\n\n // initialize read state to last message or current time if the channel is empty\n // if the user is a member, this value will be overwritten later on otherwise this ensures\n // that everything up to this point is not marked as unread\n if (userID != null) {\n const last_read = this.state.last_message_at || new Date();\n if (user) {\n this.state.read[user.id] = {\n user,\n last_read,\n unread_messages: 0,\n };\n }\n }\n\n // apply read state if part of the state\n if (state.read) {\n for (const read of state.read) {\n this.state.read[read.user.id] = {\n last_read: new Date(read.last_read),\n last_read_message_id: read.last_read_message_id,\n unread_messages: read.unread_messages ?? 0,\n user: read.user,\n };\n\n if (read.user.id === user?.id) {\n this.state.unreadCount = this.state.read[read.user.id].unread_messages;\n }\n }\n }\n\n return {\n messageSet,\n };\n }\n\n _extendEventWithOwnReactions(event: Event) {\n if (!event.message) {\n return;\n }\n const message = this.state.findMessage(event.message.id, event.message.parent_id);\n if (message) {\n event.message.own_reactions = message.own_reactions;\n }\n }\n\n _hydrateMembers({\n members,\n overrideCurrentState = true,\n }: {\n members: ChannelMemberResponse[];\n /**\n * If set to `true` then `ChannelState.members` will be overriden with the newly\n * provided `members`, setting this property to `false` will merge current `ChannelState.members`\n * object with the newly provided `members`\n * (new members with the same `userId` will replace the old ones).\n */\n overrideCurrentState?: boolean;\n }) {\n const newMembersById = members.reduce<ChannelState['members']>(\n (membersById, member) => {\n if (member.user) {\n membersById[member.user.id] = member;\n }\n return membersById;\n },\n {},\n );\n\n if (overrideCurrentState) {\n this.state.members = newMembersById;\n } else if (!overrideCurrentState && members.length) {\n this.state.members = {\n ...this.state.members,\n ...newMembersById,\n };\n }\n }\n\n _disconnect() {\n this._client.logger(\n 'info',\n `channel:disconnect() - Disconnecting the channel ${this.cid}`,\n {\n tags: ['connection', 'channel'],\n channel: this,\n },\n );\n\n this.disconnected = true;\n this.state.setIsUpToDate(false);\n }\n}\n", "import type { UserResponse } from './types';\nimport type { StreamChat } from './client';\n\n/**\n * ClientState - A container class for the client state.\n */\nexport class ClientState {\n private client: StreamChat;\n users: {\n [key: string]: UserResponse;\n };\n userChannelReferences: { [key: string]: { [key: string]: boolean } };\n constructor({ client }: { client: StreamChat }) {\n // show the status for a certain user...\n // ie online, offline etc\n this.client = client;\n this.users = {};\n // store which channels contain references to the specified user...\n this.userChannelReferences = {};\n }\n\n updateUsers(users: UserResponse[]) {\n for (const user of users) {\n this.updateUser(user);\n }\n }\n\n updateUser(user?: UserResponse) {\n if (user != null && this.client._cacheEnabled()) {\n this.users[user.id] = user;\n }\n }\n\n updateUserReference(user: UserResponse, channelID: string) {\n if (user == null || !this.client._cacheEnabled()) {\n return;\n }\n this.updateUser(user);\n if (!this.userChannelReferences[user.id]) {\n this.userChannelReferences[user.id] = {};\n }\n this.userChannelReferences[user.id][channelID] = true;\n }\n\n deleteAllChannelReference(channelID: string) {\n for (const userID in this.userChannelReferences) {\n delete this.userChannelReferences[userID][channelID];\n }\n }\n}\n", "import WebSocket from 'isomorphic-ws';\nimport {\n addConnectionEventListeners,\n chatCodes,\n convertErrorToJson,\n randomId,\n removeConnectionEventListeners,\n retryInterval,\n sleep,\n} from './utils';\nimport {\n buildWsFatalInsight,\n buildWsSuccessAfterFailureInsight,\n postInsights,\n} from './insights';\nimport type { ConnectAPIResponse, ConnectionOpen, LogLevel, UR } from './types';\nimport type { StreamChat } from './client';\nimport type { APIError } from './errors';\n\n// Type guards to check WebSocket error type\nconst isCloseEvent = (\n res: WebSocket.CloseEvent | WebSocket.Data | WebSocket.ErrorEvent,\n): res is WebSocket.CloseEvent => (res as WebSocket.CloseEvent).code !== undefined;\n\nconst isErrorEvent = (\n res: WebSocket.CloseEvent | WebSocket.Data | WebSocket.ErrorEvent,\n): res is WebSocket.ErrorEvent => (res as WebSocket.ErrorEvent).error !== undefined;\n\n/**\n * StableWSConnection - A WS connection that reconnects upon failure.\n * - the browser will sometimes report that you're online or offline\n * - the WS connection can break and fail (there is a 30s health check)\n * - sometimes your WS connection will seem to work while the user is in fact offline\n * - to speed up online/offline detection you can use the window.addEventListener('offline');\n *\n * There are 4 ways in which a connection can become unhealthy:\n * - websocket.onerror is called\n * - websocket.onclose is called\n * - the health check fails and no event is received for ~40 seconds\n * - the browser indicates the connection is now offline\n *\n * There are 2 assumptions we make about the server:\n * - state can be recovered by querying the channel again\n * - if the servers fails to publish a message to the client, the WS connection is destroyed\n */\nexport class StableWSConnection {\n // global from constructor\n client: StreamChat;\n\n // local vars\n connectionID?: string;\n connectionOpen?: ConnectAPIResponse;\n consecutiveFailures: number;\n pingInterval: number;\n healthCheckTimeoutRef?: NodeJS.Timeout;\n isConnecting: boolean;\n isDisconnected: boolean;\n isHealthy: boolean;\n isResolved?: boolean;\n lastEvent: Date | null;\n connectionCheckTimeout: number;\n connectionCheckTimeoutRef?: NodeJS.Timeout;\n rejectPromise?: (\n reason?: Error & {\n code?: string | number;\n isWSFailure?: boolean;\n StatusCode?: string | number;\n },\n ) => void;\n requestID: string | undefined;\n resolvePromise?: (value: ConnectionOpen) => void;\n totalFailures: number;\n ws?: WebSocket;\n wsID: number;\n\n constructor({ client }: { client: StreamChat }) {\n /** StreamChat client */\n this.client = client;\n /** consecutive failures influence the duration of the timeout */\n this.consecutiveFailures = 0;\n /** keep track of the total number of failures */\n this.totalFailures = 0;\n /** We only make 1 attempt to reconnect at the same time.. */\n this.isConnecting = false;\n /** To avoid reconnect if client is disconnected */\n this.isDisconnected = false;\n /** Boolean that indicates if the connection promise is resolved */\n this.isResolved = false;\n /** Boolean that indicates if we have a working connection to the server */\n this.isHealthy = false;\n /** Incremented when a new WS connection is made */\n this.wsID = 1;\n /** Store the last event time for health checks */\n this.lastEvent = null;\n /** Send a health check message every 25 seconds */\n this.pingInterval = 25 * 1000;\n this.connectionCheckTimeout = this.pingInterval + 10 * 1000;\n\n addConnectionEventListeners(this.onlineStatusChanged);\n }\n\n _log(msg: string, extra: UR = {}, level: LogLevel = 'info') {\n this.client.logger(level, 'connection:' + msg, { tags: ['connection'], ...extra });\n }\n\n setClient(client: StreamChat) {\n this.client = client;\n }\n\n /**\n * connect - Connect to the WS URL\n * the default 15s timeout allows between 2~3 tries\n * @return {ConnectAPIResponse<ChannelType, CommandType, UserType>} Promise that completes once the first health check message is received\n */\n async connect(timeout = 15000) {\n if (this.isConnecting) {\n throw Error(\n `You've called connect twice, can only attempt 1 connection at the time`,\n );\n }\n\n this.isDisconnected = false;\n\n try {\n const healthCheck = await this._connect();\n this.consecutiveFailures = 0;\n\n this._log(`connect() - Established ws connection with healthcheck: ${healthCheck}`);\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n } catch (error: any) {\n this.isHealthy = false;\n this.consecutiveFailures += 1;\n\n const e = error as APIError;\n\n if (e.code === chatCodes.TOKEN_EXPIRED && !this.client.tokenManager.isStatic()) {\n this._log(\n 'connect() - WS failure due to expired token, so going to try to reload token and reconnect',\n );\n this._reconnect({ refreshToken: true });\n } else if (!e.isWSFailure) {\n // API rejected the connection and we should not retry\n throw new Error(\n JSON.stringify({\n code: e.code,\n StatusCode: e.StatusCode,\n message: e.message,\n isWSFailure: e.isWSFailure,\n }),\n );\n }\n }\n\n return await this._waitForHealthy(timeout);\n }\n\n /**\n * _waitForHealthy polls the promise connection to see if its resolved until it times out\n * the default 15s timeout allows between 2~3 tries\n * @param timeout duration(ms)\n */\n _waitForHealthy(timeout = 15000) {\n return Promise.race([\n (async () => {\n const interval = 50; // ms\n for (let i = 0; i <= timeout; i += interval) {\n try {\n return await this.connectionOpen;\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n } catch (error: any) {\n if (i === timeout) {\n throw new Error(\n JSON.stringify({\n code: error.code,\n StatusCode: error.StatusCode,\n message: error.message,\n isWSFailure: error.isWSFailure,\n }),\n );\n }\n await sleep(interval);\n }\n }\n })(),\n (async () => {\n await sleep(timeout);\n this.isConnecting = false;\n throw new Error(\n JSON.stringify({\n code: '',\n StatusCode: '',\n message: 'initial WS connection could not be established',\n isWSFailure: true,\n }),\n );\n })(),\n ]);\n }\n\n /**\n * Builds and returns the url for websocket.\n * @private\n * @returns url string\n */\n _buildUrl = () => {\n const qs = this.client._buildWSPayload(this.requestID);\n const token = this.client.tokenManager.getToken();\n const wsUrlParams = this.client.options.wsUrlParams;\n\n const params = new URLSearchParams(wsUrlParams);\n params.set('json', qs);\n params.set('api_key', this.client.key);\n // it is expected that the autorization parameter exists even if\n // the token is undefined, so we interpolate it to be safe\n params.set('authorization', `${token}`);\n params.set('stream-auth-type', this.client.getAuthType());\n params.set('X-Stream-Client', this.client.getUserAgent());\n\n return `${this.client.wsBaseURL}/connect?${params.toString()}`;\n };\n\n /**\n * disconnect - Disconnect the connection and doesn't recover...\n *\n */\n disconnect(timeout?: number) {\n this._log(`disconnect() - Closing the websocket connection for wsID ${this.wsID}`);\n\n this.wsID += 1;\n this.isConnecting = false;\n this.isDisconnected = true;\n\n // start by removing all the listeners\n if (this.healthCheckTimeoutRef) {\n clearInterval(this.healthCheckTimeoutRef);\n }\n if (this.connectionCheckTimeoutRef) {\n clearInterval(this.connectionCheckTimeoutRef);\n }\n\n removeConnectionEventListeners(this.onlineStatusChanged);\n\n this.isHealthy = false;\n\n // remove ws handlers...\n if (this.ws && this.ws.removeAllListeners) {\n this.ws.removeAllListeners();\n }\n\n let isClosedPromise: Promise<void>;\n // and finally close...\n // Assigning to local here because we will remove it from this before the\n // promise resolves.\n const { ws } = this;\n if (ws && ws.close && ws.readyState === ws.OPEN) {\n isClosedPromise = new Promise((resolve) => {\n const onclose = (event: WebSocket.CloseEvent) => {\n this._log(\n `disconnect() - resolving isClosedPromise ${event ? 'with' : 'without'} close frame`,\n { event },\n );\n resolve();\n };\n\n ws.onclose = onclose;\n // In case we don't receive close frame websocket server in time,\n // lets not wait for more than 1 seconds.\n setTimeout(onclose, timeout != null ? timeout : 1000);\n });\n\n this._log(\n `disconnect() - Manually closed connection by calling client.disconnect()`,\n );\n\n ws.close(\n chatCodes.WS_CLOSED_SUCCESS,\n 'Manually closed connection by calling client.disconnect()',\n );\n } else {\n this._log(`disconnect() - ws connection doesn't exist or it is already closed.`);\n isClosedPromise = Promise.resolve();\n }\n\n delete this.ws;\n\n return isClosedPromise;\n }\n\n /**\n * _connect - Connect to the WS endpoint\n *\n * @return {ConnectAPIResponse<ChannelType, CommandType, UserType>} Promise that completes once the first health check message is received\n */\n async _connect() {\n if (\n this.isConnecting ||\n (this.isDisconnected && this.client.options.enableWSFallback)\n )\n return; // simply ignore _connect if it's currently trying to connect\n this.isConnecting = true;\n this.requestID = randomId();\n this.client.insightMetrics.connectionStartTimestamp = new Date().getTime();\n let isTokenReady = false;\n try {\n this._log(`_connect() - waiting for token`);\n await this.client.tokenManager.tokenReady();\n isTokenReady = true;\n } catch (e) {\n // token provider has failed before, so try again\n }\n\n try {\n if (!isTokenReady) {\n this._log(`_connect() - tokenProvider failed before, so going to retry`);\n await this.client.tokenManager.loadToken();\n }\n\n this._setupConnectionPromise();\n const wsURL = this._buildUrl();\n this._log(`_connect() - Connecting to ${wsURL}`, {\n wsURL,\n requestID: this.requestID,\n });\n this.ws = new WebSocket(wsURL);\n this.ws.onopen = this.onopen.bind(this, this.wsID);\n this.ws.onclose = this.onclose.bind(this, this.wsID);\n this.ws.onerror = this.onerror.bind(this, this.wsID);\n this.ws.onmessage = this.onmessage.bind(this, this.wsID);\n const response = await this.connectionOpen;\n this.isConnecting = false;\n\n if (response) {\n this.connectionID = response.connection_id;\n if (\n this.client.insightMetrics.wsConsecutiveFailures > 0 &&\n this.client.options.enableInsights\n ) {\n postInsights(\n 'ws_success_after_failure',\n buildWsSuccessAfterFailureInsight(this as unknown as StableWSConnection),\n );\n this.client.insightMetrics.wsConsecutiveFailures = 0;\n }\n return response;\n }\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n } catch (error: any) {\n this.isConnecting = false;\n this._log(`_connect() - Error - `, error);\n if (this.client.options.enableInsights) {\n this.client.insightMetrics.wsConsecutiveFailures++;\n this.client.insightMetrics.wsTotalFailures++;\n\n const insights = buildWsFatalInsight(\n this as unknown as StableWSConnection,\n convertErrorToJson(error as Error),\n );\n postInsights?.('ws_fatal', insights);\n }\n throw error;\n }\n }\n\n /**\n * _reconnect - Retry the connection to WS endpoint\n *\n * @param {{ interval?: number; refreshToken?: boolean }} options Following options are available\n *\n * - `interval`\t{int}\t\t\tnumber of ms that function should wait before reconnecting\n * - `refreshToken` {boolean}\treload/refresh user token be refreshed before attempting reconnection.\n */\n async _reconnect(\n options: { interval?: number; refreshToken?: boolean } = {},\n ): Promise<void> {\n this._log('_reconnect() - Initiating the reconnect');\n\n // only allow 1 connection at the time\n if (this.isConnecting || this.isHealthy) {\n this._log('_reconnect() - Abort (1) since already connecting or healthy');\n return;\n }\n\n // reconnect in case of on error or on close\n // also reconnect if the health check cycle fails\n let interval = options.interval;\n if (!interval) {\n interval = retryInterval(this.consecutiveFailures);\n }\n // reconnect, or try again after a little while...\n await sleep(interval);\n\n // Check once again if by some other call to _reconnect is active or connection is\n // already restored, then no need to proceed.\n if (this.isConnecting || this.isHealthy) {\n this._log('_reconnect() - Abort (2) since already connecting or healthy');\n return;\n }\n\n if (this.isDisconnected && this.client.options.enableWSFallback) {\n this._log('_reconnect() - Abort (3) since disconnect() is called');\n return;\n }\n\n this._log('_reconnect() - Destroying current WS connection');\n\n // cleanup the old connection\n this._destroyCurrentWSConnection();\n\n if (options.refreshToken) {\n await this.client.tokenManager.loadToken();\n }\n\n try {\n await this._connect();\n this._log('_reconnect() - Waiting for recoverCallBack');\n await this.client.recoverState();\n this._log('_reconnect() - Finished recoverCallBack');\n\n this.consecutiveFailures = 0;\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n } catch (error: any) {\n this.isHealthy = false;\n this.consecutiveFailures += 1;\n if (\n error.code === chatCodes.TOKEN_EXPIRED &&\n !this.client.tokenManager.isStatic()\n ) {\n this._log(\n '_reconnect() - WS failure due to expired token, so going to try to reload token and reconnect',\n );\n\n return this._reconnect({ refreshToken: true });\n }\n\n // reconnect on WS failures, don't reconnect if there is a code bug\n if (error.isWSFailure) {\n this._log('_reconnect() - WS failure, so going to try to reconnect');\n\n this._reconnect();\n }\n }\n this._log('_reconnect() - == END ==');\n }\n\n /**\n * onlineStatusChanged - this function is called when the browser connects or disconnects from the internet.\n *\n * @param {Event} event Event with type online or offline\n *\n */\n onlineStatusChanged = (event: Event) => {\n if (event.type === 'offline') {\n // mark the connection as down\n this._log('onlineStatusChanged() - Status changing to offline');\n this._setHealth(false);\n } else if (event.type === 'online') {\n // retry right now...\n // We check this.isHealthy, not sure if it's always\n // smart to create a new WS connection if the old one is still up and running.\n // it's possible we didn't miss any messages, so this process is just expensive and not needed.\n this._log(\n `onlineStatusChanged() - Status changing to online. isHealthy: ${this.isHealthy}`,\n );\n if (!this.isHealthy) {\n this._reconnect({ interval: 10 });\n }\n }\n };\n\n onopen = (wsID: number) => {\n if (this.wsID !== wsID) return;\n\n this._log('onopen() - onopen callback', { wsID });\n };\n\n onmessage = (wsID: number, event: WebSocket.MessageEvent) => {\n if (this.wsID !== wsID) return;\n\n this._log('onmessage() - onmessage callback', { event, wsID });\n const data = typeof event.data === 'string' ? JSON.parse(event.data) : null;\n\n // we wait till the first message before we consider the connection open..\n // the reason for this is that auth errors and similar errors trigger a ws.onopen and immediately\n // after that a ws.onclose..\n if (!this.isResolved && data) {\n this.isResolved = true;\n if (data.error) {\n this.rejectPromise?.(this._errorFromWSEvent(data, false));\n return;\n }\n\n this.resolvePromise?.(data);\n this._setHealth(true);\n }\n\n // trigger the event..\n this.lastEvent = new Date();\n\n if (data && data.type === 'health.check') {\n this.scheduleNextPing();\n }\n\n this.client.handleEvent(event);\n this.scheduleConnectionCheck();\n };\n\n onclose = (wsID: number, event: WebSocket.CloseEvent) => {\n if (this.wsID !== wsID) return;\n\n this._log('onclose() - onclose callback - ' + event.code, { event, wsID });\n\n if (event.code === chatCodes.WS_CLOSED_SUCCESS) {\n // this is a permanent error raised by stream..\n // usually caused by invalid auth details\n const error = new Error(\n `WS connection reject with error ${event.reason}`,\n ) as Error & WebSocket.CloseEvent;\n\n error.reason = event.reason;\n error.code = event.code;\n error.wasClean = event.wasClean;\n error.target = event.target;\n\n this.rejectPromise?.(error);\n this._log(`onclose() - WS connection reject with error ${event.reason}`, { event });\n } else {\n this.consecutiveFailures += 1;\n this.totalFailures += 1;\n this._setHealth(false);\n this.isConnecting = false;\n\n this.rejectPromise?.(this._errorFromWSEvent(event));\n\n this._log(`onclose() - WS connection closed. Calling reconnect ...`, { event });\n\n // reconnect if its an abnormal failure\n this._reconnect();\n }\n };\n\n onerror = (wsID: number, event: WebSocket.ErrorEvent) => {\n if (this.wsID !== wsID) return;\n\n this.consecutiveFailures += 1;\n this.totalFailures += 1;\n this._setHealth(false);\n this.isConnecting = false;\n\n this.rejectPromise?.(this._errorFromWSEvent(event));\n this._log(`onerror() - WS connection resulted into error`, { event });\n\n this._reconnect();\n };\n\n /**\n * _setHealth - Sets the connection to healthy or unhealthy.\n * Broadcasts an event in case the connection status changed.\n *\n * @param {boolean} healthy boolean indicating if the connection is healthy or not\n *\n */\n _setHealth = (healthy: boolean) => {\n if (healthy === this.isHealthy) return;\n\n this.isHealthy = healthy;\n\n if (this.isHealthy) {\n this.client.dispatchEvent({ type: 'connection.changed', online: this.isHealthy });\n return;\n }\n\n // we're offline, wait few seconds and fire and event if still offline\n setTimeout(() => {\n if (this.isHealthy) return;\n this.client.dispatchEvent({ type: 'connection.changed', online: this.isHealthy });\n }, 5000);\n };\n\n /**\n * _errorFromWSEvent - Creates an error object for the WS event\n *\n */\n _errorFromWSEvent = (\n event: WebSocket.CloseEvent | WebSocket.Data | WebSocket.ErrorEvent,\n isWSFailure = true,\n ) => {\n let code;\n let statusCode;\n let message;\n if (isCloseEvent(event)) {\n code = event.code;\n statusCode = 'unknown';\n message = event.reason;\n }\n\n if (isErrorEvent(event)) {\n code = event.error.code;\n statusCode = event.error.StatusCode;\n message = event.error.message;\n }\n\n // Keeping this `warn` level log, to avoid cluttering of error logs from ws failures.\n this._log(`_errorFromWSEvent() - WS failed with code ${code}`, { event }, 'warn');\n\n const error = new Error(\n `WS failed with code ${code} and reason - ${message}`,\n ) as Error & {\n code?: string | number;\n isWSFailure?: boolean;\n StatusCode?: string | number;\n };\n error.code = code;\n /**\n * StatusCode does not exist on any event types but has been left\n * as is to preserve JS functionality during the TS implementation\n */\n error.StatusCode = statusCode;\n error.isWSFailure = isWSFailure;\n return error;\n };\n\n /**\n * _destroyCurrentWSConnection - Removes the current WS connection\n *\n */\n _destroyCurrentWSConnection() {\n // increment the ID, meaning we will ignore all messages from the old\n // ws connection from now on.\n this.wsID += 1;\n\n try {\n this?.ws?.removeAllListeners();\n this?.ws?.close();\n } catch (e) {\n // we don't care\n }\n }\n\n /**\n * _setupPromise - sets up the this.connectOpen promise\n */\n _setupConnectionPromise = () => {\n this.isResolved = false;\n /** a promise that is resolved once ws.open is called */\n this.connectionOpen = new Promise<ConnectionOpen>((resolve, reject) => {\n this.resolvePromise = resolve;\n this.rejectPromise = reject;\n });\n };\n\n /**\n * Schedules a next health check ping for websocket.\n */\n scheduleNextPing = () => {\n if (this.healthCheckTimeoutRef) {\n clearTimeout(this.healthCheckTimeoutRef);\n }\n\n // 30 seconds is the recommended interval (messenger uses this)\n this.healthCheckTimeoutRef = setTimeout(() => {\n // send the healthcheck.., server replies with a health check event\n const data = [{ type: 'health.check', client_id: this.client.clientID }];\n // try to send on the connection\n try {\n this.ws?.send(JSON.stringify(data));\n } catch (e) {\n // error will already be detected elsewhere\n }\n }, this.pingInterval);\n };\n\n /**\n * scheduleConnectionCheck - schedules a check for time difference between last received event and now.\n * If the difference is more than 35 seconds, it means our health check logic has failed and websocket needs\n * to be reconnected.\n */\n scheduleConnectionCheck = () => {\n if (this.connectionCheckTimeoutRef) {\n clearTimeout(this.connectionCheckTimeoutRef);\n }\n\n this.connectionCheckTimeoutRef = setTimeout(() => {\n const now = new Date();\n if (\n this.lastEvent &&\n now.getTime() - this.lastEvent.getTime() > this.connectionCheckTimeout\n ) {\n this._log('scheduleConnectionCheck - going to reconnect');\n this._setHealth(false);\n this._reconnect();\n }\n }, this.connectionCheckTimeout);\n };\n}\n", "import axios from 'axios';\nimport type { StableWSConnection } from './connection';\nimport { randomId, sleep } from './utils';\n\nexport type InsightTypes = 'ws_fatal' | 'ws_success_after_failure' | 'http_hi_failed';\nexport class InsightMetrics {\n connectionStartTimestamp: number | null;\n wsConsecutiveFailures: number;\n wsTotalFailures: number;\n instanceClientId: string;\n\n constructor() {\n this.connectionStartTimestamp = null;\n this.wsTotalFailures = 0;\n this.wsConsecutiveFailures = 0;\n this.instanceClientId = randomId();\n }\n}\n\n/**\n * postInsights is not supposed to be used by end users directly within chat application, and thus is kept isolated\n * from all the client/connection code/logic.\n *\n * @param insightType\n * @param insights\n */\nexport const postInsights = async (\n insightType: InsightTypes,\n insights: Record<string, unknown>,\n) => {\n const maxAttempts = 3;\n for (let i = 0; i < maxAttempts; i++) {\n try {\n await axios.post(\n `https://chat-insights.getstream.io/insights/${insightType}`,\n insights,\n );\n } catch (e) {\n await sleep((i + 1) * 3000);\n continue;\n }\n break;\n }\n};\n\nexport function buildWsFatalInsight(\n connection: StableWSConnection,\n event: Record<string, unknown>,\n) {\n return {\n ...event,\n ...buildWsBaseInsight(connection),\n };\n}\n\nfunction buildWsBaseInsight(connection: StableWSConnection) {\n const { client } = connection;\n return {\n ready_state: connection.ws?.readyState,\n url: connection._buildUrl(),\n api_key: client.key,\n start_ts: client.insightMetrics.connectionStartTimestamp,\n end_ts: new Date().getTime(),\n auth_type: client.getAuthType(),\n token: client.tokenManager.token,\n user_id: client.userID,\n user_details: client._user,\n device: client.options.device,\n client_id: connection.connectionID,\n ws_details: connection.ws,\n ws_consecutive_failures: client.insightMetrics.wsConsecutiveFailures,\n ws_total_failures: client.insightMetrics.wsTotalFailures,\n request_id: connection.requestID,\n online: typeof navigator !== 'undefined' ? navigator?.onLine : null,\n user_agent: typeof navigator !== 'undefined' ? navigator?.userAgent : null,\n instance_client_id: client.insightMetrics.instanceClientId,\n };\n}\n\nexport function buildWsSuccessAfterFailureInsight(connection: StableWSConnection) {\n return buildWsBaseInsight(connection);\n}\n", "import jwt from 'jsonwebtoken';\nimport crypto from 'crypto';\nimport { decodeBase64, encodeBase64 } from './base64';\nimport type { UR } from './types';\n\n/**\n * Creates the JWT token that can be used for a UserSession\n * @method JWTUserToken\n * @memberof signing\n * @private\n * @param {Secret} apiSecret - API Secret key\n * @param {string} userId - The user_id key in the JWT payload\n * @param {UR} [extraData] - Extra that should be part of the JWT token\n * @param {SignOptions} [jwtOptions] - Options that can be past to jwt.sign\n * @return {string} JWT Token\n */\nexport function JWTUserToken(\n apiSecret: jwt.Secret,\n userId: string,\n extraData: UR = {},\n jwtOptions: jwt.SignOptions = {},\n) {\n if (typeof userId !== 'string') {\n throw new TypeError('userId should be a string');\n }\n\n const payload: { user_id: string } & UR = {\n user_id: userId,\n ...extraData,\n };\n\n // make sure we return a clear error when jwt is shimmed (ie. browser build)\n if (jwt == null || jwt.sign == null) {\n throw Error(\n `Unable to find jwt crypto, if you are getting this error is probably because you are trying to generate tokens on browser or React Native (or other environment where crypto functions are not available). Please Note: token should only be generated server-side.`,\n );\n }\n\n const opts: jwt.SignOptions = Object.assign(\n { algorithm: 'HS256', noTimestamp: true },\n jwtOptions,\n );\n\n if (payload.iat) {\n opts.noTimestamp = false;\n }\n return jwt.sign(payload, apiSecret, opts);\n}\n\nexport function JWTServerToken(apiSecret: jwt.Secret, jwtOptions: jwt.SignOptions = {}) {\n const payload = {\n server: true,\n };\n\n const opts: jwt.SignOptions = Object.assign(\n { algorithm: 'HS256', noTimestamp: true },\n jwtOptions,\n );\n return jwt.sign(payload, apiSecret, opts);\n}\n\nexport function UserFromToken(token: string) {\n const fragments = token.split('.');\n if (fragments.length !== 3) {\n return '';\n }\n const b64Payload = fragments[1];\n const payload = decodeBase64(b64Payload);\n const data = JSON.parse(payload);\n return data.user_id as string;\n}\n\n/**\n *\n * @param {string} userId the id of the user\n * @return {string}\n */\nexport function DevToken(userId: string) {\n return [\n 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9', //{\"alg\": \"HS256\", \"typ\": \"JWT\"}\n encodeBase64(JSON.stringify({ user_id: userId })),\n 'devtoken', // hardcoded signature\n ].join('.');\n}\n\n/**\n *\n * @param {string | Buffer} body the signed message\n * @param {string} secret the shared secret used to generate the signature (Stream API secret)\n * @param {string} signature the signature to validate\n * @return {boolean}\n */\nexport function CheckSignature(body: string | Buffer, secret: string, signature: string) {\n const key = Buffer.from(secret, 'utf8');\n const hash = crypto.createHmac('sha256', key).update(body).digest('hex');\n\n try {\n return crypto.timingSafeEqual(Buffer.from(hash), Buffer.from(signature));\n } catch {\n return false;\n }\n}\n", "import type jwt from 'jsonwebtoken';\n\nimport { JWTServerToken, JWTUserToken, UserFromToken } from './signing';\nimport { isFunction } from './utils';\nimport type { TokenOrProvider, UserResponse } from './types';\n\n/**\n * TokenManager\n *\n * Handles all the operations around user token.\n */\nexport class TokenManager {\n loadTokenPromise: Promise<string> | null;\n type: 'static' | 'provider';\n secret?: jwt.Secret;\n token?: string;\n tokenProvider?: TokenOrProvider;\n user?: UserResponse;\n /**\n * Constructor\n *\n * @param {Secret} secret\n */\n constructor(secret?: jwt.Secret) {\n this.loadTokenPromise = null;\n if (secret) {\n this.secret = secret;\n }\n\n this.type = 'static';\n\n if (this.secret) {\n this.token = JWTServerToken(this.secret);\n }\n }\n\n /**\n * Set the static string token or token provider.\n * Token provider should return a token string or a promise which resolves to string token.\n *\n * @param {TokenOrProvider} tokenOrProvider\n * @param {UserResponse} user\n */\n setTokenOrProvider = async (tokenOrProvider: TokenOrProvider, user: UserResponse) => {\n this.validateToken(tokenOrProvider, user);\n this.user = user;\n\n if (isFunction(tokenOrProvider)) {\n this.tokenProvider = tokenOrProvider;\n this.type = 'provider';\n }\n\n if (typeof tokenOrProvider === 'string') {\n this.token = tokenOrProvider;\n this.type = 'static';\n }\n\n if (!tokenOrProvider && this.user && this.secret) {\n this.token = JWTUserToken(this.secret, user.id, {}, {});\n this.type = 'static';\n }\n\n await this.loadToken();\n };\n\n /**\n * Resets the token manager.\n * Useful for client disconnection or switching user.\n */\n reset = () => {\n this.token = undefined;\n this.tokenProvider = undefined;\n this.type = 'static';\n this.user = undefined;\n this.loadTokenPromise = null;\n };\n\n // Validates the user token.\n validateToken = (tokenOrProvider: TokenOrProvider, user: UserResponse) => {\n // allow empty token for anon user\n if (user && user.anon && !tokenOrProvider) return;\n\n // Don't allow empty token for non-server side client.\n if (!this.secret && !tokenOrProvider) {\n throw new Error('User token can not be empty');\n }\n\n if (\n tokenOrProvider &&\n typeof tokenOrProvider !== 'string' &&\n !isFunction(tokenOrProvider)\n ) {\n throw new Error('user token should either be a string or a function');\n }\n\n if (typeof tokenOrProvider === 'string') {\n // Allow empty token for anonymous users\n if (user.anon && tokenOrProvider === '') return;\n\n const tokenUserId = UserFromToken(tokenOrProvider);\n if (\n tokenOrProvider != null &&\n (tokenUserId == null || tokenUserId === '' || tokenUserId !== user.id)\n ) {\n throw new Error(\n 'userToken does not have a user_id or is not matching with user.id',\n );\n }\n }\n };\n\n // Resolves when token is ready. This function is simply to check if loadToken is in progress, in which\n // case a function should wait.\n tokenReady = () => this.loadTokenPromise;\n\n // Fetches a token from tokenProvider function and sets in tokenManager.\n // In case of static token, it will simply resolve to static token.\n loadToken = () => {\n // eslint-disable-next-line no-async-promise-executor\n this.loadTokenPromise = new Promise(async (resolve, reject) => {\n if (this.type === 'static') {\n return resolve(this.token as string);\n }\n\n if (this.tokenProvider && typeof this.tokenProvider !== 'string') {\n try {\n this.token = await this.tokenProvider();\n } catch (e) {\n return reject(\n new Error(`Call to tokenProvider failed with message: ${e}`, { cause: e }),\n );\n }\n resolve(this.token);\n }\n });\n\n return this.loadTokenPromise;\n };\n\n // Returns a current token\n getToken = () => {\n if (this.token) {\n return this.token;\n }\n\n if (this.user && this.user.anon && !this.token) {\n return this.token;\n }\n\n if (this.secret) {\n return JWTServerToken(this.secret);\n }\n\n throw new Error(\n `Both secret and user tokens are not set. Either client.connectUser wasn't called or client.disconnect was called`,\n );\n };\n\n isStatic = () => this.type === 'static';\n}\n", "import type { AxiosRequestConfig, CancelTokenSource } from 'axios';\nimport axios from 'axios';\nimport type { StreamChat } from './client';\nimport {\n addConnectionEventListeners,\n removeConnectionEventListeners,\n retryInterval,\n sleep,\n} from './utils';\nimport { isAPIError, isConnectionIDError, isErrorRetryable } from './errors';\nimport type { ConnectionOpen, Event, LogLevel, UR } from './types';\n\nexport enum ConnectionState {\n Closed = 'CLOSED',\n Connected = 'CONNECTED',\n Connecting = 'CONNECTING',\n Disconnected = 'DISCONNECTED',\n Init = 'INIT',\n}\n\nexport class WSConnectionFallback {\n client: StreamChat;\n state: ConnectionState;\n consecutiveFailures: number;\n connectionID?: string;\n cancelToken?: CancelTokenSource;\n\n constructor({ client }: { client: StreamChat }) {\n this.client = client;\n this.state = ConnectionState.Init;\n this.consecutiveFailures = 0;\n\n addConnectionEventListeners(this._onlineStatusChanged);\n }\n\n _log(msg: string, extra: UR = {}, level: LogLevel = 'info') {\n this.client.logger(level, 'WSConnectionFallback:' + msg, {\n tags: ['connection_fallback', 'connection'],\n ...extra,\n });\n }\n\n _setState(state: ConnectionState) {\n this._log(`_setState() - ${state}`);\n\n // transition from connecting => connected\n if (\n this.state === ConnectionState.Connecting &&\n state === ConnectionState.Connected\n ) {\n this.client.dispatchEvent({ type: 'connection.changed', online: true });\n }\n\n if (state === ConnectionState.Closed || state === ConnectionState.Disconnected) {\n this.client.dispatchEvent({ type: 'connection.changed', online: false });\n }\n\n this.state = state;\n }\n\n /** @private */\n _onlineStatusChanged = (event: { type: string }) => {\n this._log(`_onlineStatusChanged() - ${event.type}`);\n\n if (event.type === 'offline') {\n this._setState(ConnectionState.Closed);\n this.cancelToken?.cancel('disconnect() is called');\n this.cancelToken = undefined;\n return;\n }\n\n if (event.type === 'online' && this.state === ConnectionState.Closed) {\n this.connect(true);\n }\n };\n\n /** @private */\n _req = async <T = UR>(\n params: UR,\n config: AxiosRequestConfig,\n retry: boolean,\n ): Promise<T> => {\n if (!this.cancelToken && !params.close) {\n this.cancelToken = axios.CancelToken.source();\n }\n\n try {\n const res = await this.client.doAxiosRequest<T>(\n 'get',\n (this.client.baseURL as string).replace(':3030', ':8900') + '/longpoll', // replace port if present for testing with local API\n undefined,\n {\n config: { ...config, cancelToken: this.cancelToken?.token },\n params,\n },\n );\n\n this.consecutiveFailures = 0; // always reset in case of no error\n return res;\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n } catch (error: any) {\n this.consecutiveFailures += 1;\n\n if (retry && isErrorRetryable(error)) {\n this._log(`_req() - Retryable error, retrying request`);\n await sleep(retryInterval(this.consecutiveFailures));\n return this._req<T>(params, config, retry);\n }\n\n throw error;\n }\n };\n\n /** @private */\n _poll = async () => {\n while (this.state === ConnectionState.Connected) {\n try {\n const data = await this._req<{\n events: Event[];\n }>({}, { timeout: 30000 }, true); // 30s => API responds in 20s if there is no event\n\n if (data.events?.length) {\n for (let i = 0; i < data.events.length; i++) {\n this.client.dispatchEvent(data.events[i]);\n }\n }\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n } catch (error: any) {\n if (axios.isCancel(error)) {\n this._log(`_poll() - axios canceled request`);\n return;\n }\n\n /** client.doAxiosRequest will take care of TOKEN_EXPIRED error */\n\n if (isConnectionIDError(error)) {\n this._log(`_poll() - ConnectionID error, connecting without ID...`);\n this._setState(ConnectionState.Disconnected);\n this.connect(true);\n return;\n }\n\n if (isAPIError(error) && !isErrorRetryable(error)) {\n this._setState(ConnectionState.Closed);\n return;\n }\n\n await sleep(retryInterval(this.consecutiveFailures));\n }\n }\n };\n\n /**\n * connect try to open a longpoll request\n * @param reconnect should be false for first call and true for subsequent calls to keep the connection alive and call recoverState\n */\n connect = async (reconnect = false) => {\n if (this.state === ConnectionState.Connecting) {\n this._log('connect() - connecting already in progress', { reconnect }, 'warn');\n return;\n }\n if (this.state === ConnectionState.Connected) {\n this._log('connect() - already connected and polling', { reconnect }, 'warn');\n return;\n }\n\n this._setState(ConnectionState.Connecting);\n this.connectionID = undefined; // connect should be sent with empty connection_id so API creates one\n try {\n const { event } = await this._req<{ event: ConnectionOpen }>(\n { json: this.client._buildWSPayload() },\n { timeout: 8000 }, // 8s\n reconnect,\n );\n\n this._setState(ConnectionState.Connected);\n this.connectionID = event.connection_id;\n // @ts-expect-error type mismatch\n this.client.dispatchEvent(event);\n this._poll();\n if (reconnect) {\n this.client.recoverState();\n }\n return event;\n } catch (err) {\n this._setState(ConnectionState.Closed);\n throw err;\n }\n };\n\n /**\n * isHealthy checks if there is a connectionID and connection is in Connected state\n */\n isHealthy = () => !!this.connectionID && this.state === ConnectionState.Connected;\n\n disconnect = async (timeout = 2000) => {\n removeConnectionEventListeners(this._onlineStatusChanged);\n\n this._setState(ConnectionState.Disconnected);\n this.cancelToken?.cancel('disconnect() is called');\n this.cancelToken = undefined;\n\n const connection_id = this.connectionID;\n this.connectionID = undefined;\n\n try {\n await this._req({ close: true, connection_id }, { timeout }, false);\n this._log(`disconnect() - Closed connectionID`);\n } catch (err) {\n this._log(`disconnect() - Failed`, { err }, 'error');\n }\n };\n}\n", "import type { AxiosResponse } from 'axios';\nimport type { APIErrorResponse } from './types';\n\nexport const APIErrorCodes: Record<string, { name: string; retryable: boolean }> = {\n '-1': { name: 'InternalSystemError', retryable: true },\n '2': { name: 'AccessKeyError', retryable: false },\n '3': { name: 'AuthenticationFailedError', retryable: true },\n '4': { name: 'InputError', retryable: false },\n '6': { name: 'DuplicateUsernameError', retryable: false },\n '9': { name: 'RateLimitError', retryable: true },\n '16': { name: 'DoesNotExistError', retryable: false },\n '17': { name: 'NotAllowedError', retryable: false },\n '18': { name: 'EventNotSupportedError', retryable: false },\n '19': { name: 'ChannelFeatureNotSupportedError', retryable: false },\n '20': { name: 'MessageTooLongError', retryable: false },\n '21': { name: 'MultipleNestingLevelError', retryable: false },\n '22': { name: 'PayloadTooBigError', retryable: false },\n '23': { name: 'RequestTimeoutError', retryable: true },\n '24': { name: 'MaxHeaderSizeExceededError', retryable: false },\n '40': { name: 'AuthErrorTokenExpired', retryable: false },\n '41': { name: 'AuthErrorTokenNotValidYet', retryable: false },\n '42': { name: 'AuthErrorTokenUsedBeforeIssuedAt', retryable: false },\n '43': { name: 'AuthErrorTokenSignatureInvalid', retryable: false },\n '44': { name: 'CustomCommandEndpointMissingError', retryable: false },\n '45': { name: 'CustomCommandEndpointCallError', retryable: true },\n '46': { name: 'ConnectionIDNotFoundError', retryable: false },\n '60': { name: 'CoolDownError', retryable: true },\n '69': { name: 'ErrWrongRegion', retryable: false },\n '70': { name: 'ErrQueryChannelPermissions', retryable: false },\n '71': { name: 'ErrTooManyConnections', retryable: true },\n '99': { name: 'AppSuspendedError', retryable: false },\n};\n\nexport type APIError = Error & {\n code: number;\n isWSFailure?: boolean;\n StatusCode?: number;\n};\n\nexport function isAPIError(error: Error): error is APIError {\n return (error as APIError).code !== undefined;\n}\n\nexport function isErrorRetryable(error: APIError) {\n if (!error.code) return false;\n const err = APIErrorCodes[`${error.code}`];\n if (!err) return false;\n return err.retryable;\n}\n\nexport function isConnectionIDError(error: APIError) {\n return error.code === 46; // ConnectionIDNotFoundError\n}\n\nexport function isWSFailure(err: APIError): boolean {\n if (typeof err.isWSFailure === 'boolean') {\n return err.isWSFailure;\n }\n\n try {\n return JSON.parse(err.message).isWSFailure;\n } catch (_) {\n return false;\n }\n}\n\nexport function isErrorResponse(\n res: AxiosResponse<unknown>,\n): res is AxiosResponse<APIErrorResponse> {\n return !res.status || res.status < 200 || 300 <= res.status;\n}\n", "import type { StreamChat } from './client';\nimport type {\n QuerySegmentTargetsFilter,\n SegmentData,\n SegmentResponse,\n SortParam,\n} from './types';\n\ntype SegmentType = 'user' | 'channel';\n\ntype SegmentUpdatableFields = {\n description?: string;\n filter?: {};\n name?: string;\n};\n\nexport class Segment {\n type: SegmentType;\n id: string | null;\n client: StreamChat;\n data?: SegmentData | SegmentResponse;\n\n constructor(\n client: StreamChat,\n type: SegmentType,\n id: string | null,\n data?: SegmentData,\n ) {\n this.client = client;\n this.type = type;\n this.id = id;\n this.data = data;\n }\n\n create() {\n const body = {\n name: this.data?.name,\n filter: this.data?.filter,\n description: this.data?.description,\n all_sender_channels: this.data?.all_sender_channels,\n all_users: this.data?.all_users,\n };\n\n return this.client.createSegment(this.type, this.id, body);\n }\n\n verifySegmentId() {\n if (!this.id) {\n throw new Error(\n 'Segment id is missing. Either create the segment using segment.create() or set the id during instantiation - const segment = client.segment(id)',\n );\n }\n }\n\n get() {\n this.verifySegmentId();\n return this.client.getSegment(this.id as string);\n }\n\n update(data: Partial<SegmentUpdatableFields>) {\n this.verifySegmentId();\n\n return this.client.updateSegment(this.id as string, data);\n }\n\n addTargets(targets: string[]) {\n this.verifySegmentId();\n return this.client.addSegmentTargets(this.id as string, targets);\n }\n\n removeTargets(targets: string[]) {\n this.verifySegmentId();\n return this.client.removeSegmentTargets(this.id as string, targets);\n }\n\n delete() {\n this.verifySegmentId();\n return this.client.deleteSegment(this.id as string);\n }\n\n targetExists(targetId: string) {\n this.verifySegmentId();\n return this.client.segmentTargetExists(this.id as string, targetId);\n }\n\n queryTargets(\n filter: QuerySegmentTargetsFilter | null = {},\n sort: SortParam[] | null | [] = [],\n options = {},\n ) {\n this.verifySegmentId();\n\n return this.client.querySegmentTargets(this.id as string, filter, sort, options);\n }\n}\n", "import type {\n APIResponse,\n CustomCheckFlag,\n GetConfigResponse,\n GetUserModerationReportOptions,\n GetUserModerationReportResponse,\n ModerationConfig,\n ModerationFlagOptions,\n ModerationMuteOptions,\n ModerationRule,\n ModerationRuleRequest,\n MuteUserResponse,\n Pager,\n QueryConfigsResponse,\n QueryModerationConfigsFilters,\n QueryModerationConfigsSort,\n QueryModerationRulesFilters,\n QueryModerationRulesResponse,\n QueryModerationRulesSort,\n RequireAtLeastOne,\n ReviewQueueFilters,\n ReviewQueueItem,\n ReviewQueuePaginationOptions,\n ReviewQueueResponse,\n ReviewQueueSort,\n SubmitActionOptions,\n UpsertConfigResponse,\n UpsertModerationRuleResponse,\n} from './types';\nimport type { StreamChat } from './client';\nimport { normalizeQuerySort } from './utils';\n\nexport const MODERATION_ENTITY_TYPES = {\n user: 'stream:user',\n message: 'stream:chat:v1:message',\n userprofile: 'stream:v1:user_profile',\n};\n\n// Moderation class provides all the endpoints related to moderation v2.\nexport class Moderation {\n client: StreamChat;\n\n constructor(client: StreamChat) {\n this.client = client;\n }\n\n /**\n * Flag a user\n *\n * @param {string} flaggedUserID User ID to be flagged\n * @param {string} reason Reason for flagging the user\n * @param {Object} options Additional options for flagging the user\n * @param {string} options.user_id (For server side usage) User ID of the user who is flagging the target user\n * @param {Object} options.custom Additional data to be stored with the flag\n * @returns\n */\n flagUser(flaggedUserID: string, reason: string, options: ModerationFlagOptions = {}) {\n return this.flag(MODERATION_ENTITY_TYPES.user, flaggedUserID, '', reason, options);\n }\n\n /**\n * Flag a message\n *\n * @param {string} messageID Message ID to be flagged\n * @param {string} reason Reason for flagging the message\n * @param {Object} options Additional options for flagging the message\n * @param {string} options.user_id (For server side usage) User ID of the user who is flagging the target message\n * @param {Object} options.custom Additional data to be stored with the flag\n * @returns\n */\n flagMessage(messageID: string, reason: string, options: ModerationFlagOptions = {}) {\n return this.flag(MODERATION_ENTITY_TYPES.message, messageID, '', reason, options);\n }\n\n /**\n * Flag a user\n *\n * @param {string} entityType Entity type to be flagged\n * @param {string} entityId Entity ID to be flagged\n * @param {string} entityCreatorID User ID of the entity creator\n * @param {string} reason Reason for flagging the entity\n * @param {Object} options Additional options for flagging the entity\n * @param {string} options.user_id (For server side usage) User ID of the user who is flagging the target entity\n * @param {Object} options.moderation_payload Content to be flagged e.g., { texts: ['text1', 'text2'], images: ['image1', 'image2']}\n * @param {Object} options.custom Additional data to be stored with the flag\n * @returns\n */\n async flag(\n entityType: string,\n entityId: string,\n entityCreatorID: string,\n reason: string,\n options: ModerationFlagOptions = {},\n ) {\n return await this.client.post<{ item_id: string } & APIResponse>(\n this.client.baseURL + '/api/v2/moderation/flag',\n {\n entity_type: entityType,\n entity_id: entityId,\n entity_creator_id: entityCreatorID,\n reason,\n ...options,\n },\n );\n }\n\n /**\n * Mute a user\n * @param {string} targetID User ID to be muted\n * @param {Object} options Additional options for muting the user\n * @param {string} options.user_id (For server side usage) User ID of the user who is muting the target user\n * @param {number} options.timeout Timeout for the mute in minutes\n * @returns\n */\n async muteUser(targetID: string, options: ModerationMuteOptions = {}) {\n return await this.client.post<MuteUserResponse & APIResponse>(\n this.client.baseURL + '/api/v2/moderation/mute',\n {\n target_ids: [targetID],\n ...options,\n },\n );\n }\n\n /**\n * Unmute a user\n * @param {string} targetID User ID to be unmuted\n * @param {Object} options Additional options for unmuting the user\n * @param {string} options.user_id (For server side usage) User ID of the user who is unmuting the target user\n * @returns\n */\n async unmuteUser(\n targetID: string,\n options: {\n user_id?: string;\n },\n ) {\n return await this.client.post<{ item_id: string } & APIResponse>(\n this.client.baseURL + '/api/v2/moderation/unmute',\n {\n target_ids: [targetID],\n ...options,\n },\n );\n }\n\n /**\n * Get moderation report for a user\n * @param {string} userID User ID for which moderation report is to be fetched\n * @param {Object} options Additional options for fetching the moderation report\n * @param {boolean} options.create_user_if_not_exists Create user if not exists\n * @param {boolean} options.include_user_blocks Include user blocks\n * @param {boolean} options.include_user_mutes Include user mutes\n */\n async getUserModerationReport(\n userID: string,\n options: GetUserModerationReportOptions = {},\n ) {\n return await this.client.get<GetUserModerationReportResponse>(\n this.client.baseURL + `/api/v2/moderation/user_report`,\n {\n user_id: userID,\n ...options,\n },\n );\n }\n\n /**\n * Query review queue\n * @param {Object} filterConditions Filter conditions for querying review queue\n * @param {Object} sort Sort conditions for querying review queue\n * @param {Object} options Pagination options for querying review queue\n */\n async queryReviewQueue(\n filterConditions: ReviewQueueFilters = {},\n sort: ReviewQueueSort = [],\n options: ReviewQueuePaginationOptions = {},\n ) {\n return await this.client.post<ReviewQueueResponse>(\n this.client.baseURL + '/api/v2/moderation/review_queue',\n {\n filter: filterConditions,\n sort: normalizeQuerySort(sort),\n ...options,\n },\n );\n }\n\n /**\n * Upsert moderation config\n * @param {Object} config Moderation config to be upserted\n */\n async upsertConfig(config: ModerationConfig) {\n return await this.client.post<UpsertConfigResponse>(\n this.client.baseURL + '/api/v2/moderation/config',\n config,\n );\n }\n\n /**\n * Get moderation config\n * @param {string} key Key for which moderation config is to be fetched\n */\n async getConfig(key: string, data?: { team?: string }) {\n return await this.client.get<GetConfigResponse>(\n this.client.baseURL + '/api/v2/moderation/config/' + key,\n data,\n );\n }\n\n async deleteConfig(key: string, data?: { team?: string }) {\n return await this.client.delete(\n this.client.baseURL + '/api/v2/moderation/config/' + key,\n data,\n );\n }\n\n /**\n * Query moderation configs\n * @param {Object} filterConditions Filter conditions for querying moderation configs\n * @param {Object} sort Sort conditions for querying moderation configs\n * @param {Object} options Additional options for querying moderation configs\n */\n async queryConfigs(\n filterConditions: QueryModerationConfigsFilters,\n sort: QueryModerationConfigsSort,\n options: Pager = {},\n ) {\n return await this.client.post<QueryConfigsResponse>(\n this.client.baseURL + '/api/v2/moderation/configs',\n {\n filter: filterConditions,\n sort,\n ...options,\n },\n );\n }\n\n async submitAction(\n actionType: string,\n itemID: string,\n options: SubmitActionOptions = {},\n ) {\n return await this.client.post<{ item_id: string } & APIResponse>(\n this.client.baseURL + '/api/v2/moderation/submit_action',\n {\n action_type: actionType,\n item_id: itemID,\n ...options,\n },\n );\n }\n\n /**\n *\n * @param {string} entityType string Type of entity to be checked E.g., stream:user, stream:chat:v1:message, or any custom string\n * @param {string} entityID string ID of the entity to be checked. This is mainly for tracking purposes\n * @param {string} entityCreatorID string ID of the entity creator\n * @param {object} moderationPayload object Content to be checked for moderation. E.g., { texts: ['text1', 'text2'], images: ['image1', 'image2']}\n * @param {Array} moderationPayload.texts array Array of texts to be checked for moderation\n * @param {Array} moderationPayload.images array Array of images to be checked for moderation\n * @param {Array} moderationPayload.videos array Array of videos to be checked for moderation\n * @param configKey\n * @param options\n * @returns\n */\n async check(\n entityType: string,\n entityID: string,\n entityCreatorID: string,\n moderationPayload: {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n custom?: Record<string, any>;\n images?: string[];\n texts?: string[];\n videos?: string[];\n },\n configKey: string,\n options?: {\n force_sync?: boolean;\n test_mode?: boolean;\n },\n ) {\n return await this.client.post(this.client.baseURL + `/api/v2/moderation/check`, {\n entity_type: entityType,\n entity_id: entityID,\n entity_creator_id: entityCreatorID,\n moderation_payload: moderationPayload,\n config_key: configKey,\n options,\n });\n }\n\n /**\n * Experimental: Check user profile\n *\n * Warning: This is an experimental feature and the API is subject to change.\n *\n * This function is used to check a user profile for moderation.\n * This will not create any review queue items for the user profile.\n * You can just use this to check whether to allow a certain user profile to be created or not.\n *\n * Example:\n *\n * ```ts\n * const res = await client.moderation.checkUserProfile(userId, { username: \"fuck_boy_001\", image: \"https://example.com/profile.jpg\" });\n * if (res.recommended_action === \"remove\") {\n * // Block the user profile from being created\n * } else {\n * // Allow the user profile to be created\n * }\n * ```\n *\n * @param userId\n * @param profile.username\n * @param profile.image\n * @returns\n */\n async checkUserProfile(\n userId: string,\n profile: RequireAtLeastOne<{ image?: string; username?: string }>,\n ) {\n if (!profile.username && !profile.image) {\n throw new Error('Either username or image must be provided');\n }\n\n const moderationPayload: { images?: string[]; texts?: string[] } = {};\n if (profile.username) {\n moderationPayload.texts = [profile.username];\n }\n if (profile.image) {\n moderationPayload.images = [profile.image];\n }\n\n return await this.check(\n MODERATION_ENTITY_TYPES.userprofile,\n userId,\n userId,\n moderationPayload,\n 'user_profile:default',\n {\n force_sync: true,\n test_mode: true,\n },\n );\n }\n\n /**\n *\n * @param {string} entityType string Type of entity to be checked E.g., stream:user, stream:chat:v1:message, or any custom string\n * @param {string} entityID string ID of the entity to be checked. This is mainly for tracking purposes\n * @param {string} entityCreatorID string ID of the entity creator\n * @param {object} moderationPayload object Content to be checked for moderation. E.g., { texts: ['text1', 'text2'], images: ['image1', 'image2']}\n * @param {Array} moderationPayload.texts array Array of texts to be checked for moderation\n * @param {Array} moderationPayload.images array Array of images to be checked for moderation\n * @param {Array} moderationPayload.videos array Array of videos to be checked for moderation\n * @param {Array<CustomCheckFlag>} flags Array of CustomCheckFlag to be passed to flag the entity\n * @returns\n */\n async addCustomFlags(\n entityType: string,\n entityID: string,\n entityCreatorID: string,\n moderationPayload: {\n images?: string[];\n texts?: string[];\n videos?: string[];\n },\n flags: CustomCheckFlag[],\n ) {\n return await this.client.post<\n { id: string; item: ReviewQueueItem; status: string } & APIResponse\n >(this.client.baseURL + `/api/v2/moderation/custom_check`, {\n entity_type: entityType,\n entity_id: entityID,\n entity_creator_id: entityCreatorID,\n moderation_payload: moderationPayload,\n flags,\n });\n }\n\n /**\n * Add custom flags to a message\n * @param {string} messageID Message ID to be flagged\n * @param {Array<CustomCheckFlag>} flags Array of CustomCheckFlag to be passed to flag the message\n * @returns\n */\n async addCustomMessageFlags(messageID: string, flags: CustomCheckFlag[]) {\n return await this.addCustomFlags(\n MODERATION_ENTITY_TYPES.message,\n messageID,\n '',\n {},\n flags,\n );\n }\n\n /**\n * Create or update a moderation rule\n * @param {ModerationRuleRequest} rule Rule configuration to be upserted\n * @returns\n */\n async upsertModerationRule(rule: ModerationRuleRequest) {\n return await this.client.post<UpsertModerationRuleResponse>(\n this.client.baseURL + '/api/v2/moderation/moderation_rule',\n rule,\n );\n }\n\n /**\n * Query moderation rules\n * @param {QueryModerationRulesFilters} filterConditions Filter conditions for querying moderation rules\n * @param {QueryModerationRulesSort} sort Sort conditions for querying moderation rules\n * @param {Pager} options Pagination options for querying moderation rules\n * @returns\n */\n async queryModerationRules(\n filterConditions: QueryModerationRulesFilters = {},\n sort: QueryModerationRulesSort = [],\n options: Pager = {},\n ) {\n return await this.client.post<QueryModerationRulesResponse>(\n this.client.baseURL + '/api/v2/moderation/moderation_rules',\n {\n filter: filterConditions,\n sort,\n ...options,\n },\n );\n }\n\n /**\n * Get a specific moderation rule by ID\n * @param {string} id ID of the moderation rule to fetch\n * @returns\n */\n async getModerationRule(id: string) {\n return await this.client.get<{ rule: ModerationRule }>(\n this.client.baseURL + '/api/v2/moderation/moderation_rule/' + id,\n );\n }\n\n /**\n * Delete a moderation rule by ID\n * @param {string} id ID of the moderation rule to delete\n * @returns\n */\n async deleteModerationRule(id: string) {\n return await this.client.delete(\n this.client.baseURL + '/api/v2/moderation/moderation_rule/' + id,\n );\n }\n}\n", "import { StateStore } from './store';\nimport { throttle } from './utils';\n\nimport type { StreamChat } from './client';\nimport type { Thread } from './thread';\nimport type { Event, OwnUserResponse, QueryThreadsOptions } from './types';\nimport { WithSubscriptions } from './utils/WithSubscriptions';\n\nconst DEFAULT_CONNECTION_RECOVERY_THROTTLE_DURATION = 1000;\nconst MAX_QUERY_THREADS_LIMIT = 25;\nexport const THREAD_MANAGER_INITIAL_STATE = {\n active: false,\n isThreadOrderStale: false,\n threads: [],\n unreadThreadCount: 0,\n unseenThreadIds: [],\n lastConnectionDropAt: null,\n pagination: {\n isLoading: false,\n isLoadingNext: false,\n nextCursor: null,\n },\n ready: false,\n};\n\nexport type ThreadManagerState = {\n active: boolean;\n isThreadOrderStale: boolean;\n lastConnectionDropAt: Date | null;\n pagination: ThreadManagerPagination;\n ready: boolean;\n threads: Thread[];\n unreadThreadCount: number;\n /**\n * List of threads that haven't been loaded in the list, but have received new messages\n * since the latest reload. Useful to display a banner prompting to reload the thread list.\n */\n unseenThreadIds: string[];\n};\n\nexport type ThreadManagerPagination = {\n isLoading: boolean;\n isLoadingNext: boolean;\n nextCursor: string | null;\n};\n\nexport class ThreadManager extends WithSubscriptions {\n public readonly state: StateStore<ThreadManagerState>;\n private client: StreamChat;\n private threadsByIdGetterCache: {\n threads: ThreadManagerState['threads'];\n threadsById: Record<string, Thread | undefined>;\n };\n // cache used in combination with threadsById\n // used for threads which are not stored in the list\n // private threadCache: Record<string, Thread | undefined> = {};\n\n constructor({ client }: { client: StreamChat }) {\n super();\n\n this.client = client;\n this.state = new StateStore<ThreadManagerState>(THREAD_MANAGER_INITIAL_STATE);\n\n this.threadsByIdGetterCache = { threads: [], threadsById: {} };\n }\n\n public get threadsById() {\n const { threads } = this.state.getLatestValue();\n\n if (threads === this.threadsByIdGetterCache.threads) {\n return this.threadsByIdGetterCache.threadsById;\n }\n\n const threadsById = threads.reduce<Record<string, Thread>>(\n (newThreadsById, thread) => {\n newThreadsById[thread.id] = thread;\n return newThreadsById;\n },\n {},\n );\n\n this.threadsByIdGetterCache.threads = threads;\n this.threadsByIdGetterCache.threadsById = threadsById;\n\n return threadsById;\n }\n\n public resetState = () => {\n this.state.next(THREAD_MANAGER_INITIAL_STATE);\n };\n\n public activate = () => {\n this.state.partialNext({ active: true });\n };\n\n public deactivate = () => {\n this.state.partialNext({ active: false });\n };\n\n public registerSubscriptions = () => {\n if (this.hasSubscriptions) return;\n\n this.addUnsubscribeFunction(this.subscribeUnreadThreadsCountChange());\n this.addUnsubscribeFunction(this.subscribeManageThreadSubscriptions());\n this.addUnsubscribeFunction(this.subscribeReloadOnActivation());\n this.addUnsubscribeFunction(this.subscribeNewReplies());\n this.addUnsubscribeFunction(this.subscribeRecoverAfterConnectionDrop());\n this.addUnsubscribeFunction(this.subscribeChannelDeleted());\n };\n\n private subscribeUnreadThreadsCountChange = () => {\n // initiate\n const { unread_threads: unreadThreadCount = 0 } =\n (this.client.user as OwnUserResponse) ?? {};\n this.state.partialNext({ unreadThreadCount });\n\n const unsubscribeFunctions = [\n 'health.check',\n 'notification.mark_read',\n 'notification.thread_message_new',\n 'notification.channel_deleted',\n ].map(\n (eventType) =>\n this.client.on(eventType, (event) => {\n const { unread_threads: unreadThreadCount } = event.me ?? event;\n if (typeof unreadThreadCount === 'number') {\n this.state.partialNext({ unreadThreadCount });\n }\n }).unsubscribe,\n );\n\n return () => unsubscribeFunctions.forEach((unsubscribe) => unsubscribe());\n };\n\n private subscribeChannelDeleted = () =>\n this.client.on('notification.channel_deleted', (event) => {\n const { cid } = event;\n const { threads } = this.state.getLatestValue();\n\n const newThreads = threads.filter((thread) => thread.channel.cid !== cid);\n this.state.partialNext({ threads: newThreads });\n }).unsubscribe;\n\n private subscribeManageThreadSubscriptions = () =>\n this.state.subscribeWithSelector(\n (nextValue) => ({ threads: nextValue.threads }),\n ({ threads: nextThreads }, prev) => {\n const { threads: prevThreads = [] } = prev ?? {};\n // Thread instance was removed if there's no thread with the given id at all,\n // or it was replaced with a new instance\n const removedThreads = prevThreads.filter(\n (thread) => thread !== this.threadsById[thread.id],\n );\n\n nextThreads.forEach((thread) => thread.registerSubscriptions());\n removedThreads.forEach((thread) => thread.unregisterSubscriptions());\n },\n );\n\n private subscribeReloadOnActivation = () =>\n this.state.subscribeWithSelector(\n (nextValue) => ({ active: nextValue.active }),\n ({ active }) => {\n if (active) this.reload();\n },\n );\n\n private subscribeNewReplies = () =>\n this.client.on('notification.thread_message_new', (event: Event) => {\n const parentId = event.message?.parent_id;\n if (!parentId) return;\n\n const { unseenThreadIds, ready } = this.state.getLatestValue();\n if (!ready) return;\n\n if (this.threadsById[parentId]) {\n this.state.partialNext({ isThreadOrderStale: true });\n } else if (!unseenThreadIds.includes(parentId)) {\n this.state.partialNext({ unseenThreadIds: unseenThreadIds.concat(parentId) });\n }\n }).unsubscribe;\n\n private subscribeRecoverAfterConnectionDrop = () => {\n const unsubscribeConnectionDropped = this.client.on('connection.changed', (event) => {\n if (event.online === false) {\n this.state.next((current) =>\n current.lastConnectionDropAt\n ? current\n : {\n ...current,\n lastConnectionDropAt: new Date(),\n },\n );\n }\n }).unsubscribe;\n\n const throttledHandleConnectionRecovered = throttle(\n () => {\n const { lastConnectionDropAt } = this.state.getLatestValue();\n if (!lastConnectionDropAt) return;\n this.reload({ force: true });\n },\n DEFAULT_CONNECTION_RECOVERY_THROTTLE_DURATION,\n { trailing: true },\n );\n\n const unsubscribeConnectionRecovered = this.client.on(\n 'connection.recovered',\n throttledHandleConnectionRecovered,\n ).unsubscribe;\n\n return () => {\n unsubscribeConnectionDropped();\n unsubscribeConnectionRecovered();\n };\n };\n\n public unregisterSubscriptions = () => {\n this.state\n .getLatestValue()\n .threads.forEach((thread) => thread.unregisterSubscriptions());\n return super.unregisterSubscriptions();\n };\n\n public reload = async ({ force = false } = {}) => {\n const { threads, unseenThreadIds, isThreadOrderStale, pagination, ready } =\n this.state.getLatestValue();\n if (pagination.isLoading) return;\n if (!force && ready && !unseenThreadIds.length && !isThreadOrderStale) return;\n const limit = threads.length + unseenThreadIds.length;\n\n try {\n this.state.next((current) => ({\n ...current,\n pagination: {\n ...current.pagination,\n isLoading: true,\n },\n }));\n\n const response = await this.queryThreads({\n limit: Math.min(limit, MAX_QUERY_THREADS_LIMIT) || MAX_QUERY_THREADS_LIMIT,\n });\n\n const nextThreads: Thread[] = [];\n\n for (const incomingThread of response.threads) {\n const existingThread = this.threadsById[incomingThread.id];\n\n if (existingThread) {\n // Reuse thread instances if possible\n nextThreads.push(existingThread);\n if (existingThread.hasStaleState) {\n existingThread.hydrateState(incomingThread);\n }\n } else {\n nextThreads.push(incomingThread);\n }\n }\n\n this.state.next((current) => ({\n ...current,\n threads: nextThreads,\n unseenThreadIds: [],\n isThreadOrderStale: false,\n pagination: {\n ...current.pagination,\n isLoading: false,\n nextCursor: response.next ?? null,\n },\n ready: true,\n }));\n } catch (error) {\n this.client.logger('error', (error as Error).message);\n this.state.next((current) => ({\n ...current,\n pagination: {\n ...current.pagination,\n isLoading: false,\n },\n }));\n }\n };\n\n public queryThreads = (options: QueryThreadsOptions = {}) =>\n this.client.queryThreads({\n limit: 25,\n participant_limit: 10,\n reply_limit: 10,\n watch: true,\n ...options,\n });\n\n public loadNextPage = async (options: Omit<QueryThreadsOptions, 'next'> = {}) => {\n const { pagination } = this.state.getLatestValue();\n\n if (pagination.isLoadingNext || !pagination.nextCursor) return;\n\n try {\n this.state.partialNext({ pagination: { ...pagination, isLoadingNext: true } });\n\n const response = await this.queryThreads({\n ...options,\n next: pagination.nextCursor,\n });\n\n this.state.next((current) => ({\n ...current,\n threads: response.threads.length\n ? current.threads.concat(response.threads)\n : current.threads,\n pagination: {\n ...current.pagination,\n nextCursor: response.next ?? null,\n isLoadingNext: false,\n },\n }));\n } catch (error) {\n this.client.logger('error', (error as Error).message);\n this.state.next((current) => ({\n ...current,\n pagination: {\n ...current.pagination,\n isLoadingNext: false,\n },\n }));\n }\n };\n}\n", "import { StateStore } from './store';\nimport type { StreamChat } from './client';\nimport type {\n Event,\n PartialPollUpdate,\n PollAnswer,\n PollData,\n PollEnrichData,\n PollOptionData,\n PollResponse,\n PollVote,\n QueryVotesFilters,\n QueryVotesOptions,\n VoteSort,\n} from './types';\n\ntype PollEvent = {\n cid: string;\n created_at: string;\n poll: PollResponse;\n};\n\ntype PollUpdatedEvent = PollEvent & {\n type: 'poll.updated';\n};\n\ntype PollClosedEvent = PollEvent & {\n type: 'poll.closed';\n};\n\ntype PollVoteEvent = {\n cid: string;\n created_at: string;\n poll: PollResponse;\n poll_vote: PollVote | PollAnswer;\n};\n\ntype PollVoteCastedEvent = PollVoteEvent & {\n type: 'poll.vote_casted';\n};\n\ntype PollVoteCastedChanged = PollVoteEvent & {\n type: 'poll.vote_removed';\n};\n\ntype PollVoteCastedRemoved = PollVoteEvent & {\n type: 'poll.vote_removed';\n};\n\nconst isPollUpdatedEvent = (e: Event): e is PollUpdatedEvent => e.type === 'poll.updated';\nconst isPollClosedEventEvent = (e: Event): e is PollClosedEvent =>\n e.type === 'poll.closed';\nconst isPollVoteCastedEvent = (e: Event): e is PollVoteCastedEvent =>\n e.type === 'poll.vote_casted';\nconst isPollVoteChangedEvent = (e: Event): e is PollVoteCastedChanged =>\n e.type === 'poll.vote_changed';\nconst isPollVoteRemovedEvent = (e: Event): e is PollVoteCastedRemoved =>\n e.type === 'poll.vote_removed';\n\nexport const isVoteAnswer = (vote: PollVote | PollAnswer): vote is PollAnswer =>\n !!(vote as PollAnswer)?.answer_text;\n\nexport type PollAnswersQueryParams = {\n filter?: QueryVotesFilters;\n options?: QueryVotesOptions;\n sort?: VoteSort;\n};\n\nexport type PollOptionVotesQueryParams = {\n filter: { option_id: string } & QueryVotesFilters;\n options?: QueryVotesOptions;\n sort?: VoteSort;\n};\n\ntype OptionId = string;\n\nexport type PollState = Omit<PollResponse, 'own_votes' | 'id'> & {\n lastActivityAt: Date; // todo: would be ideal to get this from the BE\n maxVotedOptionIds: OptionId[];\n ownVotesByOptionId: Record<OptionId, PollVote>;\n ownAnswer?: PollAnswer; // each user can have only one answer\n};\n\ntype PollInitOptions = {\n client: StreamChat;\n poll: PollResponse;\n};\n\nexport class Poll {\n public readonly state: StateStore<PollState>;\n public id: string;\n private client: StreamChat;\n\n constructor({ client, poll }: PollInitOptions) {\n this.client = client;\n this.id = poll.id;\n\n this.state = new StateStore<PollState>(this.getInitialStateFromPollResponse(poll));\n }\n\n private getInitialStateFromPollResponse = (poll: PollInitOptions['poll']) => {\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n const { own_votes, id, ...pollResponseForState } = poll;\n const { ownAnswer, ownVotes } = own_votes?.reduce<{\n ownVotes: PollVote[];\n ownAnswer?: PollAnswer;\n }>(\n (acc, voteOrAnswer) => {\n if (isVoteAnswer(voteOrAnswer)) {\n acc.ownAnswer = voteOrAnswer;\n } else {\n acc.ownVotes.push(voteOrAnswer);\n }\n return acc;\n },\n { ownVotes: [] },\n ) ?? { ownVotes: [] };\n\n return {\n ...pollResponseForState,\n lastActivityAt: new Date(),\n maxVotedOptionIds: getMaxVotedOptionIds(\n pollResponseForState.vote_counts_by_option as PollResponse['vote_counts_by_option'],\n ),\n ownAnswer,\n ownVotesByOptionId: getOwnVotesByOptionId(ownVotes),\n };\n };\n\n private upsertOfflineDb = () => {\n this.client.offlineDb?.executeQuerySafely(\n (db) => db.upsertPoll({ poll: mapPollStateToResponse(this) }),\n { method: 'upsertPoll' },\n );\n };\n\n public reinitializeState = (poll: PollInitOptions['poll']) => {\n this.state.partialNext(this.getInitialStateFromPollResponse(poll));\n };\n\n get data(): PollState {\n return this.state.getLatestValue();\n }\n\n public handlePollUpdated = (event: Event) => {\n if (event.poll?.id && event.poll.id !== this.id) return;\n if (!isPollUpdatedEvent(event)) return;\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n const { id, ...pollData } = extractPollData(event.poll);\n // @ts-expect-error type mismatch\n this.state.partialNext({ ...pollData, lastActivityAt: new Date(event.created_at) });\n this.upsertOfflineDb();\n };\n\n public handlePollClosed = (event: Event) => {\n if (event.poll?.id && event.poll.id !== this.id) return;\n if (!isPollClosedEventEvent(event)) return;\n this.state.partialNext({\n is_closed: true,\n lastActivityAt: new Date(event.created_at),\n });\n this.upsertOfflineDb();\n };\n\n public handleVoteCasted = (event: Event) => {\n if (event.poll?.id && event.poll.id !== this.id) return;\n if (!isPollVoteCastedEvent(event)) return;\n const currentState = this.data;\n const isOwnVote = event.poll_vote.user_id === this.client.userID;\n let latestAnswers = [...(currentState.latest_answers as PollAnswer[])];\n let ownAnswer = currentState.ownAnswer;\n const ownVotesByOptionId = currentState.ownVotesByOptionId;\n let maxVotedOptionIds = currentState.maxVotedOptionIds;\n\n if (isOwnVote) {\n if (isVoteAnswer(event.poll_vote)) {\n ownAnswer = event.poll_vote;\n } else if (event.poll_vote.option_id) {\n ownVotesByOptionId[event.poll_vote.option_id] = event.poll_vote;\n }\n }\n\n if (isVoteAnswer(event.poll_vote)) {\n latestAnswers = [event.poll_vote, ...latestAnswers];\n } else {\n maxVotedOptionIds = getMaxVotedOptionIds(event.poll.vote_counts_by_option);\n }\n\n const pollEnrichData = extractPollEnrichedData(event.poll);\n this.state.partialNext({\n ...pollEnrichData,\n latest_answers: latestAnswers,\n lastActivityAt: new Date(event.created_at),\n ownAnswer,\n ownVotesByOptionId,\n maxVotedOptionIds,\n });\n this.upsertOfflineDb();\n };\n\n public handleVoteChanged = (event: Event) => {\n // this event is triggered only when event.poll.enforce_unique_vote === true\n if (event.poll?.id && event.poll.id !== this.id) return;\n if (!isPollVoteChangedEvent(event)) return;\n const currentState = this.data;\n const isOwnVote = event.poll_vote.user_id === this.client.userID;\n let latestAnswers = [...(currentState.latest_answers as PollAnswer[])];\n let ownAnswer = currentState.ownAnswer;\n let ownVotesByOptionId = currentState.ownVotesByOptionId;\n let maxVotedOptionIds = currentState.maxVotedOptionIds;\n\n if (isOwnVote) {\n if (isVoteAnswer(event.poll_vote)) {\n latestAnswers = [\n event.poll_vote,\n ...latestAnswers.filter((answer) => answer.id !== event.poll_vote.id),\n ];\n ownAnswer = event.poll_vote;\n } else if (event.poll_vote.option_id) {\n if (event.poll.enforce_unique_vote) {\n ownVotesByOptionId = { [event.poll_vote.option_id]: event.poll_vote };\n } else {\n ownVotesByOptionId = Object.entries(ownVotesByOptionId).reduce<\n Record<OptionId, PollVote>\n >((acc, [optionId, vote]) => {\n if (\n optionId !== event.poll_vote.option_id &&\n vote.id === event.poll_vote.id\n ) {\n return acc;\n }\n acc[optionId] = vote;\n return acc;\n }, {});\n ownVotesByOptionId[event.poll_vote.option_id] = event.poll_vote;\n }\n\n if (ownAnswer?.id === event.poll_vote.id) {\n ownAnswer = undefined;\n }\n maxVotedOptionIds = getMaxVotedOptionIds(event.poll.vote_counts_by_option);\n }\n } else if (isVoteAnswer(event.poll_vote)) {\n latestAnswers = [event.poll_vote, ...latestAnswers];\n } else {\n maxVotedOptionIds = getMaxVotedOptionIds(event.poll.vote_counts_by_option);\n }\n\n const pollEnrichData = extractPollEnrichedData(event.poll);\n this.state.partialNext({\n ...pollEnrichData,\n latest_answers: latestAnswers,\n lastActivityAt: new Date(event.created_at),\n ownAnswer,\n ownVotesByOptionId,\n maxVotedOptionIds,\n });\n this.upsertOfflineDb();\n };\n\n public handleVoteRemoved = (event: Event) => {\n if (event.poll?.id && event.poll.id !== this.id) return;\n if (!isPollVoteRemovedEvent(event)) return;\n const currentState = this.data;\n const isOwnVote = event.poll_vote.user_id === this.client.userID;\n let latestAnswers = [...(currentState.latest_answers as PollAnswer[])];\n let ownAnswer = currentState.ownAnswer;\n const ownVotesByOptionId = { ...currentState.ownVotesByOptionId };\n let maxVotedOptionIds = currentState.maxVotedOptionIds;\n\n if (isVoteAnswer(event.poll_vote)) {\n latestAnswers = latestAnswers.filter((answer) => answer.id !== event.poll_vote.id);\n if (isOwnVote) {\n ownAnswer = undefined;\n }\n } else {\n maxVotedOptionIds = getMaxVotedOptionIds(event.poll.vote_counts_by_option);\n if (isOwnVote && event.poll_vote.option_id) {\n delete ownVotesByOptionId[event.poll_vote.option_id];\n }\n }\n\n const pollEnrichData = extractPollEnrichedData(event.poll);\n this.state.partialNext({\n ...pollEnrichData,\n latest_answers: latestAnswers,\n lastActivityAt: new Date(event.created_at),\n ownAnswer,\n ownVotesByOptionId,\n maxVotedOptionIds,\n });\n this.upsertOfflineDb();\n };\n\n query = async (id: string) => {\n const { poll } = await this.client.getPoll(id);\n this.state.partialNext({ ...poll, lastActivityAt: new Date() });\n return poll;\n };\n\n update = async (data: Exclude<PollData, 'id'>) =>\n await this.client.updatePoll({ ...data, id: this.id });\n\n partialUpdate = async (partialPollObject: PartialPollUpdate) =>\n await this.client.partialUpdatePoll(this.id as string, partialPollObject);\n\n close = async () => await this.client.closePoll(this.id as string);\n\n delete = async () => await this.client.deletePoll(this.id as string);\n\n createOption = async (option: PollOptionData) =>\n await this.client.createPollOption(this.id as string, option);\n\n updateOption = async (option: PollOptionData) =>\n await this.client.updatePollOption(this.id as string, option);\n\n deleteOption = async (optionId: string) =>\n await this.client.deletePollOption(this.id as string, optionId);\n\n castVote = async (optionId: string, messageId: string) => {\n const { max_votes_allowed, ownVotesByOptionId } = this.data;\n\n const reachedVoteLimit =\n max_votes_allowed && max_votes_allowed === Object.keys(ownVotesByOptionId).length;\n\n if (reachedVoteLimit) {\n this.client.notifications.addInfo({\n message: 'Reached the vote limit. Remove an existing vote first.',\n origin: {\n emitter: 'Poll',\n context: { messageId, optionId },\n },\n options: {\n type: 'validation:poll:castVote:limit',\n },\n });\n return;\n }\n return await this.client.castPollVote(messageId, this.id as string, {\n option_id: optionId,\n });\n };\n\n removeVote = async (voteId: string, messageId: string) =>\n await this.client.removePollVote(messageId, this.id as string, voteId);\n\n addAnswer = async (answerText: string, messageId: string) =>\n await this.client.addPollAnswer(messageId, this.id as string, answerText);\n\n removeAnswer = async (answerId: string, messageId: string) =>\n await this.client.removePollVote(messageId, this.id as string, answerId);\n\n queryAnswers = async (params: PollAnswersQueryParams) =>\n await this.client.queryPollAnswers(\n this.id as string,\n params.filter,\n params.sort,\n params.options,\n );\n\n queryOptionVotes = async (params: PollOptionVotesQueryParams) =>\n await this.client.queryPollVotes(\n this.id as string,\n params.filter,\n params.sort,\n params.options,\n );\n}\n\nfunction getMaxVotedOptionIds(voteCountsByOption: PollResponse['vote_counts_by_option']) {\n let maxVotes = 0;\n let winningOptions: string[] = [];\n for (const [id, count] of Object.entries(voteCountsByOption ?? {})) {\n if (count > maxVotes) {\n winningOptions = [id];\n maxVotes = count;\n } else if (count === maxVotes) {\n winningOptions.push(id);\n }\n }\n return winningOptions;\n}\n\nfunction getOwnVotesByOptionId(ownVotes: PollVote[]) {\n return !ownVotes\n ? ({} as Record<OptionId, PollVote>)\n : ownVotes.reduce<Record<OptionId, PollVote>>((acc, vote) => {\n if (isVoteAnswer(vote) || !vote.option_id) return acc;\n acc[vote.option_id] = vote;\n return acc;\n }, {});\n}\n\nexport function extractPollData(pollResponse: PollResponse): PollData {\n return {\n allow_answers: pollResponse.allow_answers,\n allow_user_suggested_options: pollResponse.allow_user_suggested_options,\n description: pollResponse.description,\n enforce_unique_vote: pollResponse.enforce_unique_vote,\n id: pollResponse.id,\n is_closed: pollResponse.is_closed,\n max_votes_allowed: pollResponse.max_votes_allowed,\n name: pollResponse.name,\n options: pollResponse.options,\n voting_visibility: pollResponse.voting_visibility,\n };\n}\n\nexport function mapPollStateToResponse(poll: Poll): PollResponse {\n const {\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n lastActivityAt,\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n maxVotedOptionIds,\n ownVotesByOptionId,\n ownAnswer,\n ...restState\n } = poll.data;\n const ownVotes = [\n ...Object.values(ownVotesByOptionId),\n ...(ownAnswer ? [ownAnswer] : []),\n ].sort((a, b) => Date.parse(a.created_at) - Date.parse(b.created_at));\n\n return {\n ...restState,\n own_votes: ownVotes,\n id: poll.id,\n };\n}\n\nexport function extractPollEnrichedData(\n pollResponse: PollResponse,\n): Omit<PollEnrichData, 'own_votes' | 'latest_answers'> {\n return {\n answers_count: pollResponse.answers_count,\n latest_votes_by_option: pollResponse.latest_votes_by_option,\n vote_count: pollResponse.vote_count,\n vote_counts_by_option: pollResponse.vote_counts_by_option,\n };\n}\n", "import type { StreamChat } from './client';\nimport type {\n CreatePollData,\n LocalMessage,\n MessageResponse,\n PollResponse,\n PollSort,\n QueryPollsFilters,\n QueryPollsOptions,\n} from './types';\nimport { Poll } from './poll';\nimport { formatMessage } from './utils';\nimport { WithSubscriptions } from './utils/WithSubscriptions';\n\nexport class PollManager extends WithSubscriptions {\n private client: StreamChat;\n // The pollCache contains only polls that have been created and sent as messages\n // (i.e only polls that are coupled with a message, can be voted on and require a\n // reactive state). It shall work as a basic look-up table for our SDK to be able\n // to quickly consume poll state that will be reactive even without the polls being\n // rendered within the UI.\n private pollCache = new Map<string, Poll>();\n\n constructor({ client }: { client: StreamChat }) {\n super();\n this.client = client;\n }\n\n get data(): Map<string, Poll> {\n return this.pollCache;\n }\n\n public fromState = (id: string) => this.pollCache.get(id);\n\n public registerSubscriptions = () => {\n if (this.hasSubscriptions) {\n // Already listening for events and changes\n return;\n }\n\n this.addUnsubscribeFunction(this.subscribeMessageNew());\n this.addUnsubscribeFunction(this.subscribePollUpdated());\n this.addUnsubscribeFunction(this.subscribePollClosed());\n this.addUnsubscribeFunction(this.subscribeVoteCasted());\n this.addUnsubscribeFunction(this.subscribeVoteChanged());\n this.addUnsubscribeFunction(this.subscribeVoteRemoved());\n };\n\n public createPoll = async (poll: CreatePollData) => {\n const { poll: createdPoll } = await this.client.createPoll(poll);\n\n if (!createdPoll.vote_counts_by_option) {\n createdPoll.vote_counts_by_option = {};\n }\n\n this.setOrOverwriteInCache(createdPoll);\n\n return this.fromState(createdPoll.id);\n };\n\n public getPoll = async (id: string) => {\n const cachedPoll = this.fromState(id);\n\n // optimistically return the cached poll if it exists and update in the background\n if (cachedPoll) {\n this.client.getPoll(id).then(({ poll }) => this.setOrOverwriteInCache(poll, true));\n return cachedPoll;\n }\n // fetch it, write to the cache and return otherwise\n const { poll } = await this.client.getPoll(id);\n\n this.setOrOverwriteInCache(poll);\n\n return this.fromState(id);\n };\n\n public queryPolls = async (\n filter: QueryPollsFilters,\n sort: PollSort = [],\n options: QueryPollsOptions = {},\n ) => {\n const { polls, next } = await this.client.queryPolls(filter, sort, options);\n\n const pollInstances = polls.map((poll) => {\n this.setOrOverwriteInCache(poll, true);\n\n return this.fromState(poll.id);\n });\n\n return {\n polls: pollInstances,\n next,\n };\n };\n\n public hydratePollCache = (\n messages: LocalMessage[] | MessageResponse[],\n overwriteState?: boolean,\n ) => {\n for (const message of messages) {\n if (!message.poll) {\n continue;\n }\n const pollResponse = message.poll as PollResponse;\n this.setOrOverwriteInCache(pollResponse, overwriteState);\n }\n };\n\n private setOrOverwriteInCache = (\n pollResponse: PollResponse,\n overwriteState?: boolean,\n ) => {\n if (!this.client._cacheEnabled()) {\n return;\n }\n const pollFromCache = this.fromState(pollResponse.id);\n if (!pollFromCache) {\n const poll = new Poll({ client: this.client, poll: pollResponse });\n this.pollCache.set(poll.id, poll);\n } else if (overwriteState) {\n pollFromCache.reinitializeState(pollResponse);\n }\n };\n\n private subscribePollUpdated = () =>\n this.client.on('poll.updated', (event) => {\n if (event.poll?.id) {\n this.fromState(event.poll.id)?.handlePollUpdated(event);\n }\n }).unsubscribe;\n\n private subscribePollClosed = () =>\n this.client.on('poll.closed', (event) => {\n if (event.poll?.id) {\n this.fromState(event.poll.id)?.handlePollClosed(event);\n }\n }).unsubscribe;\n\n private subscribeVoteCasted = () =>\n this.client.on('poll.vote_casted', (event) => {\n if (event.poll?.id) {\n this.fromState(event.poll.id)?.handleVoteCasted(event);\n }\n }).unsubscribe;\n\n private subscribeVoteChanged = () =>\n this.client.on('poll.vote_changed', (event) => {\n if (event.poll?.id) {\n this.fromState(event.poll.id)?.handleVoteChanged(event);\n }\n }).unsubscribe;\n\n private subscribeVoteRemoved = () =>\n this.client.on('poll.vote_removed', (event) => {\n if (event.poll?.id) {\n this.fromState(event.poll.id)?.handleVoteRemoved(event);\n }\n }).unsubscribe;\n\n private subscribeMessageNew = () =>\n this.client.on('message.new', (event) => {\n const { message } = event;\n if (message) {\n const formattedMessage = formatMessage(message);\n this.hydratePollCache([formattedMessage]);\n }\n }).unsubscribe;\n}\n", "import type { StreamChat } from './client';\nimport type {\n ChannelFilters,\n ChannelOptions,\n ChannelSort,\n ChannelStateOptions,\n Event,\n} from './types';\nimport type { ValueOrPatch } from './store';\nimport { isPatch, StateStore } from './store';\nimport type { Channel } from './channel';\nimport {\n extractSortValue,\n findLastPinnedChannelIndex,\n getAndWatchChannel,\n isChannelArchived,\n isChannelPinned,\n promoteChannel,\n shouldConsiderArchivedChannels,\n shouldConsiderPinnedChannels,\n sleep,\n uniqBy,\n} from './utils';\nimport { generateUUIDv4 } from './utils';\nimport {\n DEFAULT_QUERY_CHANNELS_MS_BETWEEN_RETRIES,\n DEFAULT_QUERY_CHANNELS_RETRY_COUNT,\n} from './constants';\nimport { WithSubscriptions } from './utils/WithSubscriptions';\n\nexport type ChannelManagerPagination = {\n filters: ChannelFilters;\n hasNext: boolean;\n isLoading: boolean;\n isLoadingNext: boolean;\n options: ChannelOptions;\n sort: ChannelSort;\n};\n\nexport type ChannelManagerState = {\n channels: Channel[];\n /**\n * This value will become true the first time queryChannels is successfully executed and\n * will remain false otherwise. It's used as a control property regarding whether the list\n * has been initialized yet (i.e a query has already been done at least once) or not. We do\n * this to prevent state.channels from being forced to be nullable.\n */\n initialized: boolean;\n pagination: ChannelManagerPagination;\n error: Error | undefined;\n};\n\nexport type ChannelSetterParameterType = ValueOrPatch<ChannelManagerState['channels']>;\nexport type ChannelSetterType = (arg: ChannelSetterParameterType) => void;\n\nexport type GenericEventHandlerType<T extends unknown[]> = (\n ...args: T\n) => void | (() => void) | ((...args: T) => Promise<void>) | Promise<void>;\nexport type EventHandlerType = GenericEventHandlerType<[Event]>;\nexport type EventHandlerOverrideType = GenericEventHandlerType<\n [ChannelSetterType, Event]\n>;\n\nexport type ChannelManagerEventTypes =\n | 'notification.added_to_channel'\n | 'notification.message_new'\n | 'notification.removed_from_channel'\n | 'message.new'\n | 'member.updated'\n | 'channel.deleted'\n | 'channel.hidden'\n | 'channel.truncated'\n | 'channel.visible'\n | 'channel.updated';\n\nexport type ChannelManagerEventHandlerNames =\n | 'channelDeletedHandler'\n | 'channelHiddenHandler'\n | 'channelTruncatedHandler'\n | 'channelUpdatedHandler'\n | 'channelVisibleHandler'\n | 'newMessageHandler'\n | 'memberUpdatedHandler'\n | 'notificationAddedToChannelHandler'\n | 'notificationNewMessageHandler'\n | 'notificationRemovedFromChannelHandler';\n\nexport type ChannelManagerEventHandlerOverrides = Partial<\n Record<ChannelManagerEventHandlerNames, EventHandlerOverrideType>\n>;\n\nexport type ExecuteChannelsQueryPayload = Pick<\n ChannelManagerPagination,\n 'filters' | 'sort' | 'options'\n> & { stateOptions: ChannelStateOptions };\n\nexport const channelManagerEventToHandlerMapping: {\n [key in ChannelManagerEventTypes]: ChannelManagerEventHandlerNames;\n} = {\n 'channel.deleted': 'channelDeletedHandler',\n 'channel.hidden': 'channelHiddenHandler',\n 'channel.truncated': 'channelTruncatedHandler',\n 'channel.updated': 'channelUpdatedHandler',\n 'channel.visible': 'channelVisibleHandler',\n 'message.new': 'newMessageHandler',\n 'member.updated': 'memberUpdatedHandler',\n 'notification.added_to_channel': 'notificationAddedToChannelHandler',\n 'notification.message_new': 'notificationNewMessageHandler',\n 'notification.removed_from_channel': 'notificationRemovedFromChannelHandler',\n};\n\nexport type ChannelManagerOptions = {\n /**\n * Aborts a channels query that is already in progress and runs the new one.\n */\n abortInFlightQuery?: boolean;\n /**\n * Allows channel promotion to be applied where applicable for channels that are\n * currently not part of the channel list within the state. A good example of\n * this would be a channel that is being watched and it receives a new message,\n * but is not part of the list initially.\n */\n allowNotLoadedChannelPromotionForEvent?: {\n 'channel.visible': boolean;\n 'message.new': boolean;\n 'notification.added_to_channel': boolean;\n 'notification.message_new': boolean;\n };\n /**\n * Allows us to lock the order of channels within the list. Any event that would\n * change the order of channels within the list will do nothing.\n */\n lockChannelOrder?: boolean;\n};\n\nexport type QueryChannelsRequestType = (\n ...params: Parameters<StreamChat['queryChannels']>\n) => Promise<Channel[]>;\n\nexport const DEFAULT_CHANNEL_MANAGER_OPTIONS = {\n abortInFlightQuery: false,\n allowNotLoadedChannelPromotionForEvent: {\n 'channel.visible': true,\n 'message.new': true,\n 'notification.added_to_channel': true,\n 'notification.message_new': true,\n },\n lockChannelOrder: false,\n};\n\nexport const DEFAULT_CHANNEL_MANAGER_PAGINATION_OPTIONS = {\n limit: 10,\n offset: 0,\n};\n\n/**\n * A class that manages a list of channels and changes it based on configuration and WS events. The\n * list of channels is reactive as well as the pagination and it can be subscribed to for state updates.\n *\n * @internal\n */\nexport class ChannelManager extends WithSubscriptions {\n public readonly state: StateStore<ChannelManagerState>;\n private client: StreamChat;\n private eventHandlers: Map<string, EventHandlerType> = new Map();\n private eventHandlerOverrides: Map<string, EventHandlerOverrideType> = new Map();\n private queryChannelsRequest: QueryChannelsRequestType;\n private options: ChannelManagerOptions = {};\n private stateOptions: ChannelStateOptions = {};\n private id: string;\n\n constructor({\n client,\n eventHandlerOverrides = {},\n options = {},\n queryChannelsOverride,\n }: {\n client: StreamChat;\n eventHandlerOverrides?: ChannelManagerEventHandlerOverrides;\n options?: ChannelManagerOptions;\n queryChannelsOverride?: QueryChannelsRequestType;\n }) {\n super();\n\n this.id = `channel-manager-${generateUUIDv4()}`;\n this.client = client;\n this.state = new StateStore<ChannelManagerState>({\n channels: [],\n pagination: {\n isLoading: false,\n isLoadingNext: false,\n hasNext: false,\n filters: {},\n sort: {},\n options: DEFAULT_CHANNEL_MANAGER_PAGINATION_OPTIONS,\n },\n initialized: false,\n error: undefined,\n });\n this.setEventHandlerOverrides(eventHandlerOverrides);\n this.setOptions(options);\n this.queryChannelsRequest =\n queryChannelsOverride ?? ((...params) => this.client.queryChannels(...params));\n this.eventHandlers = new Map(\n Object.entries<EventHandlerType>({\n channelDeletedHandler: this.channelDeletedHandler,\n channelHiddenHandler: this.channelHiddenHandler,\n channelVisibleHandler: this.channelVisibleHandler,\n memberUpdatedHandler: this.memberUpdatedHandler,\n newMessageHandler: this.newMessageHandler,\n notificationAddedToChannelHandler: this.notificationAddedToChannelHandler,\n notificationNewMessageHandler: this.notificationNewMessageHandler,\n notificationRemovedFromChannelHandler: this.notificationRemovedFromChannelHandler,\n }),\n );\n }\n\n public setChannels = (valueOrFactory: ChannelSetterParameterType) => {\n this.state.next((current) => {\n const { channels: currentChannels } = current;\n const newChannels = isPatch(valueOrFactory)\n ? valueOrFactory(currentChannels)\n : valueOrFactory;\n\n // If the references between the two values are the same, just return the\n // current state; otherwise trigger a state change.\n if (currentChannels === newChannels) {\n return current;\n }\n\n return { ...current, channels: newChannels };\n });\n const {\n channels,\n pagination: { filters, sort },\n } = this.state.getLatestValue();\n this.client.offlineDb?.executeQuerySafely(\n (db) =>\n db.upsertCidsForQuery({\n cids: channels.map((channel) => channel.cid),\n filters,\n sort,\n }),\n { method: 'upsertCidsForQuery' },\n );\n };\n\n public setEventHandlerOverrides = (\n eventHandlerOverrides: ChannelManagerEventHandlerOverrides = {},\n ) => {\n const truthyEventHandlerOverrides = Object.entries(eventHandlerOverrides).reduce<\n Partial<ChannelManagerEventHandlerOverrides>\n >((acc, [key, value]) => {\n if (value) {\n acc[key as keyof ChannelManagerEventHandlerOverrides] = value;\n }\n return acc;\n }, {});\n this.eventHandlerOverrides = new Map(\n Object.entries<EventHandlerOverrideType>(truthyEventHandlerOverrides),\n );\n };\n\n public setQueryChannelsRequest = (queryChannelsRequest: QueryChannelsRequestType) => {\n this.queryChannelsRequest = queryChannelsRequest;\n };\n\n public setOptions = (options: ChannelManagerOptions = {}) => {\n this.options = { ...DEFAULT_CHANNEL_MANAGER_OPTIONS, ...options };\n };\n\n private executeChannelsQuery = async (\n payload: ExecuteChannelsQueryPayload,\n retryCount = 0,\n ): Promise<void> => {\n const { filters, sort, options, stateOptions } = payload;\n const { offset, limit } = {\n ...DEFAULT_CHANNEL_MANAGER_PAGINATION_OPTIONS,\n ...options,\n };\n try {\n const channels = await this.queryChannelsRequest(\n filters,\n sort,\n options,\n stateOptions,\n );\n const newOffset = offset + (channels?.length ?? 0);\n const newOptions = { ...options, offset: newOffset };\n const { pagination } = this.state.getLatestValue();\n\n this.state.partialNext({\n channels,\n pagination: {\n ...pagination,\n hasNext: (channels?.length ?? 0) >= limit,\n isLoading: false,\n options: newOptions,\n },\n initialized: true,\n error: undefined,\n });\n this.client.offlineDb?.executeQuerySafely(\n (db) =>\n db.upsertCidsForQuery({\n cids: channels.map((channel) => channel.cid),\n filters: pagination.filters,\n sort: pagination.sort,\n }),\n { method: 'upsertCidsForQuery' },\n );\n } catch (err) {\n if (retryCount >= DEFAULT_QUERY_CHANNELS_RETRY_COUNT) {\n console.warn(err);\n\n const wrappedError = new Error(\n `Maximum number of retries reached in queryChannels. Last error message is: ${err}`,\n );\n\n const state = this.state.getLatestValue();\n // If the offline support is enabled, and there are channels in the DB, we should not error out.\n const isOfflineSupportEnabledWithChannels =\n this.client.offlineDb && state.channels.length > 0;\n\n this.state.partialNext({\n error: isOfflineSupportEnabledWithChannels ? undefined : wrappedError,\n pagination: {\n ...state.pagination,\n isLoading: false,\n isLoadingNext: false,\n },\n });\n return;\n }\n\n await sleep(DEFAULT_QUERY_CHANNELS_MS_BETWEEN_RETRIES);\n\n return this.executeChannelsQuery(payload, retryCount + 1);\n }\n };\n\n public queryChannels = async (\n filters: ChannelFilters,\n sort: ChannelSort = [],\n options: ChannelOptions = {},\n stateOptions: ChannelStateOptions = {},\n ) => {\n const {\n pagination: { isLoading, filters: filtersFromState },\n initialized,\n } = this.state.getLatestValue();\n\n if (\n isLoading &&\n !this.options.abortInFlightQuery &&\n // TODO: Figure a proper way to either deeply compare these or\n // create hashes from each.\n JSON.stringify(filtersFromState) === JSON.stringify(filters)\n ) {\n return;\n }\n\n const executeChannelsQueryPayload = { filters, sort, options, stateOptions };\n\n try {\n this.stateOptions = stateOptions;\n this.state.next((currentState) => ({\n ...currentState,\n pagination: {\n ...currentState.pagination,\n isLoading: true,\n isLoadingNext: false,\n filters,\n sort,\n options,\n },\n error: undefined,\n }));\n\n if (this.client.offlineDb?.getChannelsForQuery && this.client.user?.id) {\n if (!initialized) {\n const channelsFromDB = await this.client.offlineDb.getChannelsForQuery({\n userId: this.client.user.id,\n filters,\n sort,\n });\n\n if (channelsFromDB) {\n const offlineChannels = this.client.hydrateActiveChannels(channelsFromDB, {\n offlineMode: true,\n skipInitialization: [], // passing empty array will clear out the existing messages from channel state, this removes the possibility of duplicate messages\n });\n\n this.state.partialNext({ channels: offlineChannels });\n }\n }\n\n if (!this.client.offlineDb.syncManager.syncStatus) {\n this.client.offlineDb.syncManager.scheduleSyncStatusChangeCallback(\n this.id,\n async () => {\n await this.executeChannelsQuery(executeChannelsQueryPayload);\n },\n );\n return;\n }\n }\n await this.executeChannelsQuery(executeChannelsQueryPayload);\n } catch (error) {\n this.client.logger('error', (error as Error).message);\n this.state.next((currentState) => ({\n ...currentState,\n pagination: { ...currentState.pagination, isLoading: false },\n }));\n throw error;\n }\n };\n\n public loadNext = async () => {\n const { pagination, initialized } = this.state.getLatestValue();\n const { filters, sort, options, isLoadingNext, hasNext } = pagination;\n\n if (!initialized || isLoadingNext || !hasNext) {\n return;\n }\n\n try {\n const { offset, limit } = {\n ...DEFAULT_CHANNEL_MANAGER_PAGINATION_OPTIONS,\n ...options,\n };\n this.state.partialNext({\n pagination: { ...pagination, isLoading: false, isLoadingNext: true },\n });\n const nextChannels = await this.queryChannelsRequest(\n filters,\n sort,\n options,\n this.stateOptions,\n );\n const { channels } = this.state.getLatestValue();\n const newOffset = offset + (nextChannels?.length ?? 0);\n const newOptions = { ...options, offset: newOffset };\n\n this.state.partialNext({\n channels: uniqBy<Channel>([...(channels || []), ...nextChannels], 'cid'),\n pagination: {\n ...pagination,\n hasNext: (nextChannels?.length ?? 0) >= limit,\n isLoading: false,\n isLoadingNext: false,\n options: newOptions,\n },\n });\n } catch (error) {\n this.client.logger('error', (error as Error).message);\n this.state.next((currentState) => ({\n ...currentState,\n pagination: {\n ...currentState.pagination,\n isLoadingNext: false,\n isLoading: false,\n },\n }));\n throw error;\n }\n };\n\n private notificationAddedToChannelHandler = async (event: Event) => {\n const { id, type, members } = event?.channel ?? {};\n\n if (\n !type ||\n !this.options.allowNotLoadedChannelPromotionForEvent?.[\n 'notification.added_to_channel'\n ]\n ) {\n return;\n }\n\n const channel = await getAndWatchChannel({\n client: this.client,\n id,\n members: members?.reduce<string[]>((acc, { user, user_id }) => {\n const userId = user_id || user?.id;\n if (userId) {\n acc.push(userId);\n }\n return acc;\n }, []),\n type,\n });\n\n const { pagination, channels } = this.state.getLatestValue();\n if (!channels) {\n return;\n }\n\n const { sort } = pagination ?? {};\n\n this.setChannels(\n promoteChannel({\n channels,\n channelToMove: channel,\n sort,\n }),\n );\n };\n\n private channelDeletedHandler = (event: Event) => {\n const { channels } = this.state.getLatestValue();\n if (!channels) {\n return;\n }\n\n const newChannels = [...channels];\n const channelIndex = newChannels.findIndex(\n (channel) => channel.cid === (event.cid || event.channel?.cid),\n );\n\n if (channelIndex < 0) {\n return;\n }\n\n newChannels.splice(channelIndex, 1);\n this.setChannels(newChannels);\n };\n\n private channelHiddenHandler = this.channelDeletedHandler;\n\n private newMessageHandler = (event: Event) => {\n const { pagination, channels } = this.state.getLatestValue();\n if (!channels) {\n return;\n }\n const { filters, sort } = pagination ?? {};\n\n const channelType = event.channel_type;\n const channelId = event.channel_id;\n\n if (!channelType || !channelId) {\n return;\n }\n\n const targetChannel = this.client.channel(channelType, channelId);\n const targetChannelIndex = channels.indexOf(targetChannel);\n const targetChannelExistsWithinList = targetChannelIndex >= 0;\n\n const isTargetChannelPinned = isChannelPinned(targetChannel);\n const isTargetChannelArchived = isChannelArchived(targetChannel);\n\n const considerArchivedChannels = shouldConsiderArchivedChannels(filters);\n const considerPinnedChannels = shouldConsiderPinnedChannels(sort);\n\n if (\n // filter is defined, target channel is archived and filter option is set to false\n (considerArchivedChannels && isTargetChannelArchived && !filters.archived) ||\n // filter is defined, target channel isn't archived and filter option is set to true\n (considerArchivedChannels && !isTargetChannelArchived && filters.archived) ||\n // sort option is defined, target channel is pinned\n (considerPinnedChannels && isTargetChannelPinned) ||\n // list order is locked\n this.options.lockChannelOrder ||\n // target channel is not within the loaded list and loading from cache is disallowed\n (!targetChannelExistsWithinList &&\n !this.options.allowNotLoadedChannelPromotionForEvent?.['message.new'])\n ) {\n return;\n }\n\n this.setChannels(\n promoteChannel({\n channels,\n channelToMove: targetChannel,\n channelToMoveIndexWithinChannels: targetChannelIndex,\n sort,\n }),\n );\n };\n\n private notificationNewMessageHandler = async (event: Event) => {\n const { id, type } = event?.channel ?? {};\n\n if (!id || !type) {\n return;\n }\n\n const channel = await getAndWatchChannel({\n client: this.client,\n id,\n type,\n });\n\n const { channels, pagination } = this.state.getLatestValue();\n const { filters, sort } = pagination ?? {};\n\n const considerArchivedChannels = shouldConsiderArchivedChannels(filters);\n const isTargetChannelArchived = isChannelArchived(channel);\n\n if (\n !channels ||\n (considerArchivedChannels && isTargetChannelArchived && !filters.archived) ||\n (considerArchivedChannels && !isTargetChannelArchived && filters.archived) ||\n !this.options.allowNotLoadedChannelPromotionForEvent?.['notification.message_new']\n ) {\n return;\n }\n\n this.setChannels(\n promoteChannel({\n channels,\n channelToMove: channel,\n sort,\n }),\n );\n };\n\n private channelVisibleHandler = async (event: Event) => {\n const { channel_type: channelType, channel_id: channelId } = event;\n\n if (!channelType || !channelId) {\n return;\n }\n\n const channel = await getAndWatchChannel({\n client: this.client,\n id: event.channel_id,\n type: event.channel_type,\n });\n\n const { channels, pagination } = this.state.getLatestValue();\n const { sort, filters } = pagination ?? {};\n\n const considerArchivedChannels = shouldConsiderArchivedChannels(filters);\n const isTargetChannelArchived = isChannelArchived(channel);\n\n if (\n !channels ||\n (considerArchivedChannels && isTargetChannelArchived && !filters.archived) ||\n (considerArchivedChannels && !isTargetChannelArchived && filters.archived) ||\n !this.options.allowNotLoadedChannelPromotionForEvent?.['channel.visible']\n ) {\n return;\n }\n\n this.setChannels(\n promoteChannel({\n channels,\n channelToMove: channel,\n sort,\n }),\n );\n };\n\n private notificationRemovedFromChannelHandler = this.channelDeletedHandler;\n\n private memberUpdatedHandler = (event: Event) => {\n const { pagination, channels } = this.state.getLatestValue();\n const { filters, sort } = pagination;\n if (\n !event.member?.user ||\n event.member.user.id !== this.client.userID ||\n !event.channel_type ||\n !event.channel_id\n ) {\n return;\n }\n const channelType = event.channel_type;\n const channelId = event.channel_id;\n\n const considerPinnedChannels = shouldConsiderPinnedChannels(sort);\n const considerArchivedChannels = shouldConsiderArchivedChannels(filters);\n const pinnedAtSort = extractSortValue({ atIndex: 0, sort, targetKey: 'pinned_at' });\n\n if (\n !channels ||\n (!considerPinnedChannels && !considerArchivedChannels) ||\n this.options.lockChannelOrder\n ) {\n return;\n }\n\n const targetChannel = this.client.channel(channelType, channelId);\n // assumes that channel instances are not changing\n const targetChannelIndex = channels.indexOf(targetChannel);\n const targetChannelExistsWithinList = targetChannelIndex >= 0;\n\n const isTargetChannelPinned = isChannelPinned(targetChannel);\n const isTargetChannelArchived = isChannelArchived(targetChannel);\n\n const newChannels = [...channels];\n\n if (targetChannelExistsWithinList) {\n newChannels.splice(targetChannelIndex, 1);\n }\n\n // handle archiving (remove channel)\n if (\n // When archived filter true, and channel is unarchived\n (considerArchivedChannels && !isTargetChannelArchived && filters?.archived) ||\n // When archived filter false, and channel is archived\n (considerArchivedChannels && isTargetChannelArchived && !filters?.archived)\n ) {\n this.setChannels(newChannels);\n return;\n }\n\n // handle pinning\n let lastPinnedChannelIndex: number | null = null;\n\n if (pinnedAtSort === 1 || (pinnedAtSort === -1 && !isTargetChannelPinned)) {\n lastPinnedChannelIndex = findLastPinnedChannelIndex({ channels: newChannels });\n }\n const newTargetChannelIndex =\n typeof lastPinnedChannelIndex === 'number' ? lastPinnedChannelIndex + 1 : 0;\n\n // skip state update if the position of the channel does not change\n if (channels[newTargetChannelIndex] === targetChannel) {\n return;\n }\n\n newChannels.splice(newTargetChannelIndex, 0, targetChannel);\n this.setChannels(newChannels);\n };\n\n private subscriptionOrOverride = (event: Event) => {\n const handlerName =\n channelManagerEventToHandlerMapping[event.type as ChannelManagerEventTypes];\n const defaultEventHandler = this.eventHandlers.get(handlerName);\n const eventHandlerOverride = this.eventHandlerOverrides.get(handlerName);\n if (eventHandlerOverride && typeof eventHandlerOverride === 'function') {\n eventHandlerOverride(this.setChannels, event);\n return;\n }\n\n if (defaultEventHandler && typeof defaultEventHandler === 'function') {\n defaultEventHandler(event);\n }\n };\n\n public registerSubscriptions = () => {\n if (this.hasSubscriptions) {\n // Already listening for events and changes\n return;\n }\n\n for (const eventType of Object.keys(channelManagerEventToHandlerMapping)) {\n this.addUnsubscribeFunction(\n this.client.on(eventType, this.subscriptionOrOverride).unsubscribe,\n );\n }\n };\n}\n", "import type { NotificationManagerConfig } from './types';\n\nconst DURATION_MS = 3000 as const;\n\nexport const DEFAULT_NOTIFICATION_MANAGER_CONFIG: NotificationManagerConfig = {\n durations: {\n error: DURATION_MS,\n info: DURATION_MS,\n success: DURATION_MS,\n warning: DURATION_MS,\n },\n};\n", "import { StateStore } from '../store';\nimport { generateUUIDv4 } from '../utils';\nimport type {\n AddNotificationPayload,\n Notification,\n NotificationManagerConfig,\n NotificationState,\n} from './types';\nimport { mergeWith } from '../utils/mergeWith';\nimport { DEFAULT_NOTIFICATION_MANAGER_CONFIG } from './configuration';\n\nexport class NotificationManager {\n store: StateStore<NotificationState>;\n private timeouts: Map<string, NodeJS.Timeout> = new Map();\n config: NotificationManagerConfig;\n\n constructor(config: Partial<NotificationManagerConfig> = {}) {\n this.store = new StateStore<NotificationState>({ notifications: [] });\n this.config = mergeWith(DEFAULT_NOTIFICATION_MANAGER_CONFIG, config);\n }\n\n get notifications() {\n return this.store.getLatestValue().notifications;\n }\n\n get warning() {\n return this.notifications.filter((n) => n.severity === 'warning');\n }\n\n get error() {\n return this.notifications.filter((n) => n.severity === 'error');\n }\n\n get info() {\n return this.notifications.filter((n) => n.severity === 'info');\n }\n\n get success() {\n return this.notifications.filter((n) => n.severity === 'success');\n }\n\n add({ message, origin, options = {} }: AddNotificationPayload): string {\n const id = generateUUIDv4();\n const now = Date.now();\n const severity = options.severity || 'info';\n const duration = options.duration ?? this.config.durations[severity];\n\n const notification: Notification = {\n id,\n message,\n origin,\n type: options?.type,\n severity,\n createdAt: now,\n expiresAt: now + duration,\n actions: options.actions,\n metadata: options.metadata,\n originalError: options.originalError,\n };\n\n this.store.partialNext({\n notifications: [...this.store.getLatestValue().notifications, notification],\n });\n\n if (notification.expiresAt) {\n const timeout = setTimeout(() => {\n this.remove(id);\n }, options.duration || this.config.durations[notification.severity]);\n\n this.timeouts.set(id, timeout);\n }\n\n return id;\n }\n\n addError({ message, origin, options }: AddNotificationPayload) {\n return this.add({ message, origin, options: { ...options, severity: 'error' } });\n }\n\n addWarning({ message, origin, options }: AddNotificationPayload) {\n return this.add({ message, origin, options: { ...options, severity: 'warning' } });\n }\n\n addInfo({ message, origin, options }: AddNotificationPayload) {\n return this.add({ message, origin, options: { ...options, severity: 'info' } });\n }\n\n addSuccess({ message, origin, options }: AddNotificationPayload) {\n return this.add({ message, origin, options: { ...options, severity: 'success' } });\n }\n\n remove(id: string): void {\n const timeout = this.timeouts.get(id);\n if (timeout) {\n clearTimeout(timeout);\n this.timeouts.delete(id);\n }\n\n this.store.partialNext({\n notifications: this.store.getLatestValue().notifications.filter((n) => n.id !== id),\n });\n }\n\n clear(): void {\n this.timeouts.forEach((timeout) => clearTimeout(timeout));\n this.timeouts.clear();\n\n this.store.partialNext({ notifications: [] });\n }\n}\n", "import { timeLeftMs } from './Reminder';\nimport type { Reminder } from './Reminder';\n\nconst oneMinute = 60 * 1000;\nconst oneHour = 60 * oneMinute;\nconst oneDay = 24 * oneHour;\nconst oneWeek = 7 * oneDay;\n\nconst GROUP_BOUNDS = {\n minute: { lower: oneMinute, upper: oneHour },\n hour: { lower: oneHour, upper: oneDay },\n day: { lower: oneDay, upper: oneWeek },\n} as const;\n\nexport const DEFAULT_STOP_REFRESH_BOUNDARY_MS = 2 * oneWeek;\n\nexport type ReminderTimerConfig = {\n stopRefreshBoundaryMs?: number;\n};\n\nexport class ReminderTimer {\n reminder: Reminder;\n timeout: ReturnType<typeof setTimeout> | null = null;\n stopRefreshBoundaryMs: number = DEFAULT_STOP_REFRESH_BOUNDARY_MS;\n\n constructor({\n reminder,\n config,\n }: {\n reminder: Reminder;\n config?: ReminderTimerConfig;\n }) {\n this.reminder = reminder;\n\n if (typeof config?.stopRefreshBoundaryMs === 'number') {\n this.stopRefreshBoundaryMs = config.stopRefreshBoundaryMs;\n }\n }\n\n getRefreshIntervalLength = () => {\n if (!this.reminder.remindAt) return null;\n const distanceFromDeadlineMs = Math.abs(timeLeftMs(this.reminder.remindAt.getTime()));\n let refreshInterval: number | null;\n if (distanceFromDeadlineMs === 0) {\n refreshInterval = oneMinute;\n } else if (distanceFromDeadlineMs < GROUP_BOUNDS.minute.lower) {\n refreshInterval = distanceFromDeadlineMs;\n } else if (distanceFromDeadlineMs <= GROUP_BOUNDS.minute.upper) {\n refreshInterval = oneMinute;\n } else if (distanceFromDeadlineMs <= GROUP_BOUNDS.hour.upper) {\n refreshInterval = oneHour;\n } else {\n refreshInterval = oneDay;\n }\n return refreshInterval;\n };\n\n init = () => {\n if (!this.reminder.remindAt) return null;\n const timeoutLength = this.getRefreshIntervalLength();\n if (timeoutLength === null) return null;\n\n const boundaryTimestamp =\n this.reminder.remindAt?.getTime() + this.stopRefreshBoundaryMs;\n const timeLeftToBoundary = boundaryTimestamp - Date.now();\n\n if (timeLeftToBoundary <= 0) {\n this.timeout = null;\n return;\n }\n\n if (this.timeout) clearTimeout(this.timeout);\n\n this.timeout = setTimeout(() => {\n this.reminder.refreshTimeLeft();\n this.init();\n }, timeoutLength);\n };\n\n clear = () => {\n if (this.timeout) {\n clearInterval(this.timeout);\n this.timeout = null;\n }\n };\n}\n", "import { ReminderTimer } from './ReminderTimer';\nimport { StateStore } from '../store';\nimport type { ReminderTimerConfig } from './ReminderTimer';\nimport type { MessageResponse, ReminderResponseBase, UserResponse } from '../types';\n\nexport const timeLeftMs = (remindAt: number) => remindAt - new Date().getTime();\n\nexport type ReminderResponseBaseOrResponse = ReminderResponseBase & {\n user?: UserResponse;\n message?: MessageResponse;\n};\n\nexport type ReminderState = {\n channel_cid: string;\n created_at: Date;\n message: MessageResponse | null;\n message_id: string;\n remind_at: Date | null;\n timeLeftMs: number | null;\n updated_at: Date;\n user: UserResponse | null;\n user_id: string;\n};\n\nexport type ReminderOptions = {\n data: ReminderResponseBaseOrResponse;\n config?: ReminderTimerConfig;\n};\n\nexport class Reminder {\n state: StateStore<ReminderState>;\n timer: ReminderTimer;\n constructor({ data, config }: ReminderOptions) {\n this.state = new StateStore(Reminder.toStateValue(data));\n this.timer = new ReminderTimer({ reminder: this, config });\n this.initTimer();\n }\n\n static toStateValue = (data: ReminderResponseBaseOrResponse): ReminderState => ({\n ...data,\n created_at: new Date(data.created_at),\n message: data.message || null,\n remind_at: data.remind_at ? new Date(data.remind_at) : null,\n timeLeftMs: data.remind_at ? timeLeftMs(new Date(data.remind_at).getTime()) : null,\n updated_at: new Date(data.updated_at),\n user: data.user || null,\n });\n\n get id() {\n return this.state.getLatestValue().message_id;\n }\n\n get remindAt() {\n return this.state.getLatestValue().remind_at;\n }\n\n get timeLeftMs() {\n return this.state.getLatestValue().timeLeftMs;\n }\n\n setState = (data: ReminderResponseBaseOrResponse) => {\n this.state.next((current) => {\n const newState = { ...current, ...Reminder.toStateValue(data) };\n if (newState.remind_at) {\n newState.timeLeftMs = timeLeftMs(newState.remind_at.getTime());\n }\n return newState;\n });\n\n if (data.remind_at) {\n this.initTimer();\n } else if (!data.remind_at) {\n this.clearTimer();\n }\n };\n\n refreshTimeLeft = () => {\n if (!this.remindAt) return;\n this.state.partialNext({ timeLeftMs: timeLeftMs(this.remindAt.getTime()) });\n };\n\n initTimer = () => {\n this.timer.init();\n };\n\n clearTimer = () => {\n this.timer.clear();\n };\n}\n", "import { Reminder } from './Reminder';\nimport { DEFAULT_STOP_REFRESH_BOUNDARY_MS } from './ReminderTimer';\nimport { StateStore } from '../store';\nimport { ReminderPaginator } from '../pagination';\nimport { WithSubscriptions } from '../utils/WithSubscriptions';\nimport type { ReminderResponseBaseOrResponse } from './Reminder';\nimport type { StreamChat } from '../client';\nimport type {\n CreateReminderOptions,\n Event,\n EventTypes,\n LocalMessage,\n MessageResponse,\n ReminderResponse,\n} from '../types';\n\nconst oneMinute = 60 * 1000;\nconst oneHour = 60 * oneMinute;\nconst oneDay = 24 * oneHour;\n\nexport const DEFAULT_REMINDER_MANAGER_CONFIG: ReminderManagerConfig = {\n scheduledOffsetsMs: [\n 2 * oneMinute,\n 30 * oneMinute,\n oneHour,\n 2 * oneHour,\n 8 * oneHour,\n oneDay,\n ],\n stopTimerRefreshBoundaryMs: DEFAULT_STOP_REFRESH_BOUNDARY_MS,\n};\n\nconst isReminderExistsError = (error: Error) =>\n error.message.match('already has reminder created for this message_id');\n\nconst isReminderDoesNotExistError = (error: Error) =>\n error.message.match('reminder does not exist');\n\ntype MessageId = string;\n\nexport type ReminderEvent = {\n cid: string;\n created_at: string;\n message_id: MessageId;\n reminder: ReminderResponse;\n type: EventTypes;\n user_id: string;\n};\n\nexport type ReminderManagerState = {\n reminders: Map<MessageId, Reminder>;\n};\n\nexport type ReminderManagerConfig = {\n scheduledOffsetsMs: number[];\n stopTimerRefreshBoundaryMs: number;\n};\n\nexport type ReminderManagerOptions = {\n client: StreamChat;\n config?: Partial<ReminderManagerConfig>;\n};\n\nexport class ReminderManager extends WithSubscriptions {\n private client: StreamChat;\n configState: StateStore<ReminderManagerConfig>;\n state: StateStore<ReminderManagerState>;\n paginator: ReminderPaginator;\n\n constructor({ client, config }: ReminderManagerOptions) {\n super();\n this.client = client;\n this.configState = new StateStore({\n scheduledOffsetsMs:\n config?.scheduledOffsetsMs ?? DEFAULT_REMINDER_MANAGER_CONFIG.scheduledOffsetsMs,\n stopTimerRefreshBoundaryMs:\n config?.stopTimerRefreshBoundaryMs ??\n DEFAULT_REMINDER_MANAGER_CONFIG.stopTimerRefreshBoundaryMs,\n });\n this.state = new StateStore({ reminders: new Map<MessageId, Reminder>() });\n this.paginator = new ReminderPaginator(client);\n }\n\n // Config API START //\n updateConfig(config: Partial<ReminderManagerConfig>) {\n if (\n typeof config.stopTimerRefreshBoundaryMs === 'number' &&\n config.stopTimerRefreshBoundaryMs !== this.stopTimerRefreshBoundaryMs\n ) {\n this.reminders.forEach((reminder) => {\n reminder.timer.stopRefreshBoundaryMs =\n config?.stopTimerRefreshBoundaryMs as number;\n });\n }\n this.configState.partialNext(config);\n }\n\n get stopTimerRefreshBoundaryMs() {\n return this.configState.getLatestValue().stopTimerRefreshBoundaryMs;\n }\n\n get scheduledOffsetsMs() {\n return this.configState.getLatestValue().scheduledOffsetsMs;\n }\n // Config API END //\n\n // State API START //\n get reminders() {\n return this.state.getLatestValue().reminders;\n }\n getFromState(messageId: MessageId) {\n return this.reminders.get(messageId);\n }\n\n upsertToState = ({\n data,\n overwrite = true,\n }: {\n data: ReminderResponseBaseOrResponse;\n overwrite?: boolean;\n }) => {\n if (!this.client._cacheEnabled()) {\n return;\n }\n const cachedReminder = this.getFromState(data.message_id);\n if (!cachedReminder) {\n const reminder = new Reminder({\n data,\n config: { stopRefreshBoundaryMs: this.stopTimerRefreshBoundaryMs },\n });\n this.state.partialNext({\n reminders: new Map(this.reminders.set(data.message_id, reminder)),\n });\n } else if (overwrite) {\n cachedReminder.setState(data);\n }\n return cachedReminder;\n };\n\n removeFromState = (messageId: string) => {\n const cachedReminder = this.getFromState(messageId);\n if (!cachedReminder) return;\n cachedReminder.clearTimer();\n const reminders = this.reminders;\n reminders.delete(messageId);\n this.state.partialNext({ reminders: new Map(reminders) });\n };\n\n hydrateState = (messages: MessageResponse[] | LocalMessage[]) => {\n messages.forEach(({ reminder }) => {\n if (reminder) {\n this.upsertToState({ data: reminder });\n }\n });\n };\n // State API END //\n\n // Timers API START //\n initTimers = () => {\n this.reminders.forEach((reminder) => reminder.initTimer());\n };\n\n clearTimers = () => {\n this.reminders.forEach((reminder) => reminder.clearTimer());\n };\n // Timers API END //\n\n // WS event handling START //\n static isReminderWsEventPayload = (event: Event): event is ReminderEvent =>\n !!event.reminder &&\n (event.type.startsWith('reminder.') || event.type === 'notification.reminder_due');\n\n public registerSubscriptions = () => {\n if (this.hasSubscriptions) return;\n this.addUnsubscribeFunction(this.subscribeReminderCreated());\n this.addUnsubscribeFunction(this.subscribeReminderUpdated());\n this.addUnsubscribeFunction(this.subscribeReminderDeleted());\n this.addUnsubscribeFunction(this.subscribeNotificationReminderDue());\n this.addUnsubscribeFunction(this.subscribeMessageDeleted());\n this.addUnsubscribeFunction(this.subscribeMessageUndeleted());\n this.addUnsubscribeFunction(this.subscribePaginatorStateUpdated());\n this.addUnsubscribeFunction(this.subscribeConfigStateUpdated());\n };\n\n private subscribeReminderCreated = () =>\n this.client.on('reminder.created', (event) => {\n if (!ReminderManager.isReminderWsEventPayload(event)) return;\n const { reminder } = event;\n this.upsertToState({ data: reminder });\n }).unsubscribe;\n\n private subscribeReminderUpdated = () =>\n this.client.on('reminder.updated', (event) => {\n if (!ReminderManager.isReminderWsEventPayload(event)) return;\n const { reminder } = event;\n this.upsertToState({ data: reminder });\n }).unsubscribe;\n\n private subscribeReminderDeleted = () =>\n this.client.on('reminder.deleted', (event) => {\n if (!ReminderManager.isReminderWsEventPayload(event)) return;\n this.removeFromState(event.message_id);\n }).unsubscribe;\n\n private subscribeMessageDeleted = () =>\n this.client.on('message.deleted', (event) => {\n if (!event.message?.id) return;\n this.removeFromState(event.message.id);\n }).unsubscribe;\n\n private subscribeMessageUndeleted = () =>\n this.client.on('message.undeleted', (event) => {\n if (!event.message?.reminder) return;\n // todo: not sure whether reminder specific event is emitted too and this can be ignored here\n this.upsertToState({ data: event.message.reminder });\n }).unsubscribe;\n\n private subscribeNotificationReminderDue = () =>\n this.client.on('notification.reminder_due', () => null).unsubscribe; // todo: what should be performed on this event?\n\n private subscribePaginatorStateUpdated = () =>\n this.paginator.state.subscribeWithSelector(\n ({ items }) => [items],\n ([items]) => {\n if (!items) return;\n for (const reminder of items) {\n this.upsertToState({ data: reminder });\n }\n },\n );\n\n private subscribeConfigStateUpdated = () =>\n this.configState.subscribeWithSelector(\n ({ stopTimerRefreshBoundaryMs }) => ({ stopTimerRefreshBoundaryMs }),\n ({ stopTimerRefreshBoundaryMs }, previousValue) => {\n if (\n typeof stopTimerRefreshBoundaryMs === 'number' &&\n stopTimerRefreshBoundaryMs !== previousValue?.stopTimerRefreshBoundaryMs\n ) {\n this.reminders.forEach((reminder: Reminder) => {\n if (reminder.timer) {\n reminder.timer.stopRefreshBoundaryMs = stopTimerRefreshBoundaryMs;\n }\n });\n }\n },\n );\n // WS event handling END //\n\n // API calls START //\n upsertReminder = async (options: CreateReminderOptions) => {\n const { messageId } = options;\n if (this.getFromState(messageId)) {\n try {\n return await this.updateReminder(options);\n } catch (error) {\n if (isReminderDoesNotExistError(error as Error)) {\n return await this.createReminder(options);\n }\n throw error;\n }\n } else {\n try {\n return await this.createReminder(options);\n } catch (error) {\n if (isReminderExistsError(error as Error)) {\n return await this.updateReminder(options);\n }\n throw error;\n }\n }\n };\n\n createReminder = async (options: CreateReminderOptions) => {\n const { reminder } = await this.client.createReminder(options);\n return this.upsertToState({ data: reminder, overwrite: false });\n };\n\n updateReminder = async (options: CreateReminderOptions) => {\n const { reminder } = await this.client.updateReminder(options);\n return this.upsertToState({ data: reminder });\n };\n\n deleteReminder = async (messageId: MessageId) => {\n await this.client.deleteReminder(messageId);\n this.removeFromState(messageId);\n };\n\n queryNextReminders = async () => {\n await this.paginator.next();\n };\n\n queryPreviousReminders = async () => {\n await this.paginator.prev();\n };\n\n // API calls END //\n}\n", "export const EVENT_MAP = {\n 'channel.created': true,\n 'channel.deleted': true,\n 'channel.hidden': true,\n 'channel.kicked': true,\n 'channel.muted': true,\n 'channel.truncated': true,\n 'channel.unmuted': true,\n 'channel.updated': true,\n 'channel.visible': true,\n 'draft.deleted': true,\n 'draft.updated': true,\n 'health.check': true,\n 'member.added': true,\n 'member.removed': true,\n 'member.updated': true,\n 'message.deleted': true,\n 'message.new': true,\n 'message.read': true,\n 'message.updated': true,\n 'message.undeleted': true,\n 'notification.added_to_channel': true,\n 'notification.channel_deleted': true,\n 'notification.channel_mutes_updated': true,\n 'notification.channel_truncated': true,\n 'notification.invite_accepted': true,\n 'notification.invite_rejected': true,\n 'notification.invited': true,\n 'notification.mark_read': true,\n 'notification.mark_unread': true,\n 'notification.message_new': true,\n 'notification.mutes_updated': true,\n 'notification.removed_from_channel': true,\n 'notification.thread_message_new': true,\n 'poll.closed': true,\n 'poll.updated': true,\n 'poll.vote_casted': true,\n 'poll.vote_changed': true,\n 'poll.vote_removed': true,\n 'reaction.deleted': true,\n 'reaction.new': true,\n 'reaction.updated': true,\n 'thread.updated': true,\n 'typing.start': true,\n 'typing.stop': true,\n 'user.banned': true,\n 'user.deleted': true,\n 'user.messages.deleted': true,\n 'user.presence.changed': true,\n 'user.unbanned': true,\n 'user.unread_message_reminder': true,\n 'user.updated': true,\n 'user.watching.start': true,\n 'user.watching.stop': true,\n // AI events\n 'ai_indicator.update': true,\n 'ai_indicator.stop': true,\n 'ai_indicator.clear': true,\n\n // local events\n 'channels.queried': true,\n 'offline_reactions.queried': true,\n 'connection.changed': true,\n 'connection.recovered': true,\n 'transport.changed': true,\n 'capabilities.changed': true,\n 'live_location_sharing.started': true,\n 'live_location_sharing.stopped': true,\n\n // Reminder events\n 'reminder.created': true,\n 'reminder.updated': true,\n 'reminder.deleted': true,\n 'notification.reminder_due': true,\n};\n", "import type { PermissionObject } from './types';\n\ntype RequiredPermissionObject = Required<PermissionObject>;\n\nexport const Allow = 'Allow';\nexport const Deny = 'Deny';\nexport const AnyResource = ['*'];\nexport const AnyRole = ['*'];\nexport const MaxPriority = 999;\nexport const MinPriority = 1;\n\n// deprecated permission object class, you should use the new permission system v2 and use permissions\n// defined in BuiltinPermissions to configure your channel types\n\nexport class Permission {\n name: RequiredPermissionObject['name'];\n action: RequiredPermissionObject['action'];\n owner: RequiredPermissionObject['owner'];\n priority: RequiredPermissionObject['priority'];\n resources: RequiredPermissionObject['resources'];\n roles: RequiredPermissionObject['roles'];\n constructor(\n name: string,\n priority: number,\n resources = AnyResource,\n roles = AnyRole,\n owner = false,\n action: RequiredPermissionObject['action'] = Allow,\n ) {\n this.name = name;\n this.action = action;\n this.owner = owner;\n this.priority = priority;\n this.resources = resources;\n this.roles = roles;\n }\n}\n\n// deprecated\nexport const AllowAll = new Permission(\n 'Allow all',\n MaxPriority,\n AnyResource,\n AnyRole,\n false,\n Allow,\n);\n\n// deprecated\nexport const DenyAll = new Permission(\n 'Deny all',\n MinPriority,\n AnyResource,\n AnyRole,\n false,\n Deny,\n);\n\nexport type Role =\n | 'admin'\n | 'user'\n | 'guest'\n | 'anonymous'\n | 'channel_member'\n | 'channel_moderator'\n | (string & {});\n\nexport const BuiltinRoles = {\n Admin: 'admin',\n Anonymous: 'anonymous',\n ChannelMember: 'channel_member',\n ChannelModerator: 'channel_moderator',\n Guest: 'guest',\n User: 'user',\n};\n\nexport const BuiltinPermissions = {\n AddLinks: 'Add Links',\n BanUser: 'Ban User',\n CreateChannel: 'Create Channel',\n CreateMessage: 'Create Message',\n CreateReaction: 'Create Reaction',\n DeleteAnyAttachment: 'Delete Any Attachment',\n DeleteAnyChannel: 'Delete Any Channel',\n DeleteAnyMessage: 'Delete Any Message',\n DeleteAnyReaction: 'Delete Any Reaction',\n DeleteOwnAttachment: 'Delete Own Attachment',\n DeleteOwnChannel: 'Delete Own Channel',\n DeleteOwnMessage: 'Delete Own Message',\n DeleteOwnReaction: 'Delete Own Reaction',\n ReadAnyChannel: 'Read Any Channel',\n ReadOwnChannel: 'Read Own Channel',\n RunMessageAction: 'Run Message Action',\n UpdateAnyChannel: 'Update Any Channel',\n UpdateAnyMessage: 'Update Any Message',\n UpdateMembersAnyChannel: 'Update Members Any Channel',\n UpdateMembersOwnChannel: 'Update Members Own Channel',\n UpdateOwnChannel: 'Update Own Channel',\n UpdateOwnMessage: 'Update Own Message',\n UploadAttachment: 'Upload Attachment',\n UseFrozenChannel: 'Send messages and reactions to frozen channels',\n};\n", "import type {\n AppSettingsAPIResponse,\n ChannelAPIResponse,\n ChannelFilters,\n ChannelMemberResponse,\n ChannelResponse,\n ChannelSort,\n DraftResponse,\n LocalMessage,\n MessageResponse,\n PollResponse,\n ReactionFilters,\n ReactionResponse,\n ReactionSort,\n ReadResponse,\n} from '../types';\nimport type { Channel } from '../channel';\nimport type { StreamChat } from '../client';\n\nexport type PrepareBatchDBQueries =\n | [string]\n | [string, Array<unknown> | Array<Array<unknown>>];\n\n/**\n * Options to insert a reaction into a message.\n */\nexport type DBInsertReactionType = {\n /** Message to which the reaction is applied. */\n message: MessageResponse | LocalMessage;\n /** The reaction to insert. */\n reaction: ReactionResponse;\n /** Whether to immediately execute the operation. */\n execute?: boolean;\n};\n\n/**\n * Options to upsert channel IDs associated with a query.\n */\nexport type DBUpsertCidsForQueryType = {\n /** Array of channel IDs. */\n cids: string[];\n /** Optional filters for the channels. */\n filters?: ChannelFilters;\n /** Whether to immediately execute the operation. */\n execute?: boolean;\n /** Optional sorting applied to the channels. */\n sort?: ChannelSort;\n};\n\n/**\n * Options to upsert multiple channels.\n */\nexport type DBUpsertChannelsType = {\n /** Array of channel API responses. */\n channels: ChannelAPIResponse[];\n /** Whether to immediately execute the operation. */\n execute?: boolean;\n /** If true, marks that the latest messages are already set. */\n isLatestMessagesSet?: boolean;\n};\n\n/**\n * Options to upsert application settings for a user.\n */\nexport type DBUpsertAppSettingsType = {\n /** App settings data. */\n appSettings: AppSettingsAPIResponse;\n /** ID of the user the settings belong to. */\n userId: string;\n /** Whether to immediately execute the operation. */\n execute?: boolean;\n};\n\n/**\n * Sync status information for a user.\n */\nexport type DBUpsertUserSyncStatusType = {\n /** ID of the user. */\n userId: string;\n /** ISO timestamp of the last sync. */\n lastSyncedAt: string;\n /** Whether to immediately execute the operation. */\n execute?: boolean;\n};\n\n/**\n * Options to upsert a poll.\n */\nexport type DBUpsertPollType = {\n /** Poll data to be stored. */\n poll: PollResponse;\n /** Whether to immediately execute the operation. */\n execute?: boolean;\n};\n\n/**\n * Options to upsert individual channel data.\n */\nexport type DBUpsertChannelDataType = {\n /** Channel data. */\n channel: ChannelResponse;\n /** Whether to immediately execute the operation. */\n execute?: boolean;\n};\n\n/**\n * Options to upsert read statuses for a channel.\n */\nexport type DBUpsertReadsType = {\n /** Channel ID. */\n cid: string;\n /** Array of read statuses. */\n reads: ReadResponse[];\n /** Whether to immediately execute the operation. */\n execute?: boolean;\n};\n\n/**\n * Options to upsert multiple messages.\n */\nexport type DBUpsertMessagesType = {\n /** Array of message responses. */\n messages: MessageResponse[];\n /** Whether to immediately execute the operation. */\n execute?: boolean;\n};\n\n/**\n * Options to upsert members in a channel.\n */\nexport type DBUpsertMembersType = {\n /** Channel ID. */\n cid: string;\n /** Array of channel members. */\n members: ChannelMemberResponse[];\n /** Whether to immediately execute the operation. */\n execute?: boolean;\n};\n\n/**\n * Options to update a reaction.\n */\nexport type DBUpdateReactionType = {\n /** Message associated with the reaction. */\n message: MessageResponse | LocalMessage;\n /** The updated reaction. */\n reaction: ReactionResponse;\n /** Whether to immediately execute the operation. */\n execute?: boolean;\n};\n\n/**\n * Options to update a message.\n */\nexport type DBUpdateMessageType = {\n /** Message to update. */\n message: MessageResponse | LocalMessage;\n /** Whether to immediately execute the operation. */\n execute?: boolean;\n};\n\n/**\n * Options to get channels by their IDs.\n */\nexport type DBGetChannelsType = {\n /** Array of channel IDs. */\n cids: string[];\n /** ID of the user. */\n userId: string;\n};\n\n/**\n * Options to get channels based on filters.\n */\nexport type DBGetChannelsForQueryType = {\n /** ID of the user. */\n userId: string;\n /** Optional filters for channels. */\n filters?: ChannelFilters;\n /** Optional sorting for the channels. */\n sort?: ChannelSort;\n};\n\n/**\n * Get the last sync timestamp for a user.\n */\nexport type DBGetLastSyncedAtType = {\n /** ID of the user. */\n userId: string;\n};\n\n/**\n * Options to fetch pending tasks for a specific message.\n */\nexport type DBGetPendingTasksType = {\n /** Optional message ID to filter tasks. */\n messageId?: string;\n};\n\n/**\n * Get application settings for a user.\n */\nexport type DBGetAppSettingsType = {\n /** ID of the user. */\n userId: string;\n};\n\n/**\n * Options to retrieve reactions for a message.\n */\nexport type DBGetReactionsType = {\n /** ID of the message. */\n messageId: string;\n /** Optional filter to apply to reactions. */\n filters?: Pick<ReactionFilters, 'type'>;\n /** Optional sorting for reactions. */\n sort?: ReactionSort;\n /** Optional maximum number of reactions to return. */\n limit?: number;\n};\n\n/**\n * Delete a pending task by ID.\n */\nexport type DBDeletePendingTaskType = {\n /** ID of the pending task. */\n id: number;\n};\n\n/**\n * Options to delete a reaction from a message.\n */\nexport type DBDeleteReactionType = {\n /** The reaction to delete. */\n reaction: ReactionResponse;\n /** Optional message associated with the reaction. */\n message?: MessageResponse | LocalMessage;\n /** Whether to immediately execute the operation. */\n execute?: boolean;\n};\n\n/**\n * Options to delete a channel member.\n */\nexport type DBDeleteMemberType = {\n /** Channel ID. */\n cid: string;\n /** Member to remove. */\n member: ChannelMemberResponse;\n /** Whether to immediately execute the operation. */\n execute?: boolean;\n};\n\n/**\n * Options to drop all pending tasks for a message.\n */\nexport type DBDropPendingTasksType = {\n /** ID of the message. */\n messageId: string;\n /** Whether to immediately execute the operation. */\n execute?: boolean;\n};\n\n/**\n * Options to delete a message.\n */\nexport type DBDeleteMessageType = {\n /** ID of the message. */\n id: string;\n /** Whether to immediately execute the operation. */\n execute?: boolean;\n};\n\n/**\n * Options to delete a channel.\n */\nexport type DBDeleteChannelType = {\n /** Channel ID. */\n cid: string;\n /** Whether to immediately execute the operation. */\n execute?: boolean;\n};\n\n/**\n * Options to delete messages in a channel.\n */\nexport type DBDeleteMessagesForChannelType = {\n /** Channel ID. */\n cid: string;\n /** Timestamp before which messages are deleted. */\n truncated_at?: string;\n /** Whether to immediately execute the operation. */\n execute?: boolean;\n};\n\n/**\n * Check if a channel exists by ID.\n */\nexport type DBChannelExistsType = {\n /** Channel ID. */\n cid: string;\n};\n\nexport type DBUpsertDraftType = {\n /** Draft message to upsert. */\n draft: DraftResponse;\n /** Whether to immediately execute the operation. */\n execute?: boolean;\n};\n\nexport type DBGetDraftType = {\n /** Channel ID for which to get the draft. */\n cid: string;\n /** ID of the user requesting the draft. */\n userId: string;\n /** Optional parent ID for the parent message in thread, if applicable. */\n parent_id?: string;\n};\n\nexport type DBDeleteDraftType = {\n /** Channel ID for which to delete the draft. */\n cid: string;\n /** Optional parent ID for the parent message in thread, if applicable. */\n parent_id?: string;\n /** Whether to immediately execute the operation. */\n execute?: boolean;\n};\n\n/**\n * Represents a list of batch SQL queries to be executed.\n */\nexport type ExecuteBatchDBQueriesType = PrepareBatchDBQueries[];\n\nexport interface OfflineDBApi {\n insertReaction: (options: DBInsertReactionType) => Promise<ExecuteBatchDBQueriesType>;\n upsertCidsForQuery: (\n options: DBUpsertCidsForQueryType,\n ) => Promise<ExecuteBatchDBQueriesType>;\n upsertChannels: (options: DBUpsertChannelsType) => Promise<ExecuteBatchDBQueriesType>;\n upsertUserSyncStatus: (\n options: DBUpsertUserSyncStatusType,\n ) => Promise<ExecuteBatchDBQueriesType>;\n upsertAppSettings: (\n options: DBUpsertAppSettingsType,\n ) => Promise<ExecuteBatchDBQueriesType>;\n upsertDraft: (options: DBUpsertDraftType) => Promise<ExecuteBatchDBQueriesType>;\n upsertPoll: (options: DBUpsertPollType) => Promise<ExecuteBatchDBQueriesType>;\n upsertChannelData: (\n options: DBUpsertChannelDataType,\n ) => Promise<ExecuteBatchDBQueriesType>;\n upsertReads: (options: DBUpsertReadsType) => Promise<ExecuteBatchDBQueriesType>;\n upsertMessages: (options: DBUpsertMessagesType) => Promise<ExecuteBatchDBQueriesType>;\n upsertMembers: (options: DBUpsertMembersType) => Promise<ExecuteBatchDBQueriesType>;\n updateReaction: (options: DBUpdateReactionType) => Promise<ExecuteBatchDBQueriesType>;\n updateMessage: (options: DBUpdateMessageType) => Promise<ExecuteBatchDBQueriesType>;\n getDraft: (options: DBGetDraftType) => Promise<DraftResponse | null>;\n getChannels: (\n options: DBGetChannelsType,\n ) => Promise<Omit<ChannelAPIResponse, 'duration'>[] | null>;\n getChannelsForQuery: (\n options: DBGetChannelsForQueryType,\n ) => Promise<Omit<ChannelAPIResponse, 'duration'>[] | null>;\n getAllChannelCids: () => Promise<string[]>;\n getLastSyncedAt: (options: DBGetLastSyncedAtType) => Promise<string | undefined>;\n getAppSettings: (\n options: DBGetAppSettingsType,\n ) => Promise<AppSettingsAPIResponse | null>;\n getReactions: (options: DBGetReactionsType) => Promise<ReactionResponse[] | null>;\n executeSqlBatch: (queries: ExecuteBatchDBQueriesType) => Promise<unknown>;\n addPendingTask: (task: PendingTask) => Promise<() => Promise<void>>;\n getPendingTasks: (conditions?: DBGetPendingTasksType) => Promise<PendingTask[]>;\n deleteDraft: (options: DBDeleteDraftType) => Promise<ExecuteBatchDBQueriesType>;\n deletePendingTask: (\n options: DBDeletePendingTaskType,\n ) => Promise<ExecuteBatchDBQueriesType>;\n deleteReaction: (options: DBDeleteReactionType) => Promise<ExecuteBatchDBQueriesType>;\n deleteMember: (options: DBDeleteMemberType) => Promise<ExecuteBatchDBQueriesType>;\n deleteChannel: (options: DBDeleteChannelType) => Promise<ExecuteBatchDBQueriesType>;\n deleteMessagesForChannel: (\n options: DBDeleteMessagesForChannelType,\n ) => Promise<ExecuteBatchDBQueriesType>;\n dropPendingTasks: (\n options: DBDropPendingTasksType,\n ) => Promise<ExecuteBatchDBQueriesType>;\n hardDeleteMessage: (options: DBDeleteMessageType) => Promise<ExecuteBatchDBQueriesType>;\n softDeleteMessage: (options: DBDeleteMessageType) => Promise<ExecuteBatchDBQueriesType>;\n resetDB: () => Promise<unknown>;\n channelExists: (options: DBChannelExistsType) => Promise<boolean>;\n initializeDB: () => Promise<boolean>;\n}\n\nexport type OfflineDBState = {\n initialized: boolean;\n userId?: string;\n};\n\nexport type PendingTaskTypes = {\n deleteMessage: 'delete-message';\n deleteReaction: 'delete-reaction';\n sendReaction: 'send-reaction';\n sendMessage: 'send-message';\n createDraft: 'create-draft';\n deleteDraft: 'delete-draft';\n};\n\n// TODO: Please rethink the definition of PendingTasks as it seems awkward\nexport type PendingTask = {\n channelId?: string;\n channelType?: string;\n messageId?: string;\n id?: number;\n threadId?: string;\n} & (\n | {\n payload: Parameters<Channel['sendReaction']>;\n type: PendingTaskTypes['sendReaction'];\n }\n | {\n payload: Parameters<StreamChat['deleteMessage']>;\n type: PendingTaskTypes['deleteMessage'];\n }\n | {\n payload: Parameters<Channel['deleteReaction']>;\n type: PendingTaskTypes['deleteReaction'];\n }\n | {\n payload: Parameters<Channel['sendMessage']>;\n type: PendingTaskTypes['sendMessage'];\n }\n | {\n payload: Parameters<Channel['createDraft']>;\n type: PendingTaskTypes['createDraft'];\n }\n | {\n payload: Parameters<Channel['deleteDraft']>;\n type: PendingTaskTypes['deleteDraft'];\n }\n);\n\nexport type OfflineErrorType = 'connection:lost';\n\nexport class OfflineError extends Error {\n public type: OfflineErrorType;\n public name = 'OfflineError';\n\n constructor(\n message: string,\n {\n type,\n }: {\n type: OfflineError['type'];\n },\n ) {\n super(message);\n this.type = type;\n }\n\n // Vitest helper (serialized errors are too large to read)\n // https://github.com/vitest-dev/vitest/blob/v3.1.3/packages/utils/src/error.ts#L60-L62\n toJSON() {\n return {\n message: `${this.type} - ${this.message}`,\n stack: this.stack,\n name: this.name,\n };\n }\n}\n", "import type { ExecuteBatchDBQueriesType } from './types';\nimport type { StreamChat } from '../client';\nimport type { AbstractOfflineDB } from './offline_support_api';\nimport type { AxiosError } from 'axios';\nimport { isAxiosError } from 'axios';\nimport type { APIErrorResponse } from '../types';\n\n/**\n * Manages synchronization between the local offline database and the Stream backend.\n *\n * Responsible for detecting connection changes, syncing channel data, and executing\n * pending tasks queued during offline periods. This class ensures the database remains\n * consistent with the server once connectivity is restored.\n */\nexport class OfflineDBSyncManager {\n public syncStatus = false;\n public connectionChangedListener: { unsubscribe: () => void } | null = null;\n private syncStatusListeners: Array<(status: boolean) => void> = [];\n private scheduledSyncStatusCallbacks: Map<string | symbol, () => Promise<void>> =\n new Map();\n private client: StreamChat;\n private offlineDb: AbstractOfflineDB;\n\n constructor({\n client,\n offlineDb,\n }: {\n client: StreamChat;\n offlineDb: AbstractOfflineDB;\n }) {\n this.client = client;\n this.offlineDb = offlineDb;\n }\n\n /**\n * Initializes the sync manager. Should only be called once per session.\n *\n * Cleans up old listeners if re-initialized to avoid memory leaks.\n * Starts syncing immediately if already connected, otherwise waits for reconnection.\n */\n public init = async () => {\n try {\n // If the websocket connection is already active, then call\n // the sync api straight away and also execute pending api calls.\n // Otherwise wait for the `connection.changed` event.\n if (this.client.user?.id && this.client.wsConnection?.isHealthy) {\n await this.syncAndExecutePendingTasks();\n await this.invokeSyncStatusListeners(true);\n }\n\n // If a listener has already been registered, unsubscribe from it so\n // that it can be reinstated. This can happen if we reconnect with a\n // different user or the component invoking the init() function gets\n // unmounted and then remounted again. This part of the code makes\n // sure the stale listener doesn't produce a memory leak.\n if (this.connectionChangedListener) {\n this.connectionChangedListener.unsubscribe();\n }\n\n this.connectionChangedListener = this.client.on(\n 'connection.changed',\n async (event) => {\n if (event.online) {\n await this.syncAndExecutePendingTasks();\n await this.invokeSyncStatusListeners(true);\n } else {\n await this.invokeSyncStatusListeners(false);\n }\n },\n );\n } catch (error) {\n console.log('Error in DBSyncManager.init: ', error);\n }\n };\n\n /**\n * Registers a listener that is called whenever the sync status changes.\n *\n * @param listener - A callback invoked with the new sync status (`true` or `false`).\n * @returns An object with an `unsubscribe` function to remove the listener.\n */\n public onSyncStatusChange = (listener: (status: boolean) => void) => {\n this.syncStatusListeners.push(listener);\n\n return {\n unsubscribe: () => {\n this.syncStatusListeners = this.syncStatusListeners.filter(\n (el) => el !== listener,\n );\n },\n };\n };\n\n /**\n * Schedules a one-time callback to be invoked after the next successful sync.\n *\n * @param tag - A unique key to identify and manage the callback.\n * @param callback - An async function to run after sync.\n */\n public scheduleSyncStatusChangeCallback = (\n tag: string | symbol,\n callback: () => Promise<void>,\n ) => {\n this.scheduledSyncStatusCallbacks.set(tag, callback);\n };\n\n /**\n * Invokes all registered sync status listeners and executes any scheduled sync callbacks.\n *\n * @param status - The new sync status (`true` or `false`).\n */\n private invokeSyncStatusListeners = async (status: boolean) => {\n this.syncStatus = status;\n this.syncStatusListeners.forEach((l) => l(status));\n\n if (status) {\n const promises = Array.from(this.scheduledSyncStatusCallbacks.values()).map((cb) =>\n cb(),\n );\n await Promise.all(promises);\n\n this.scheduledSyncStatusCallbacks.clear();\n }\n };\n\n /**\n * Performs synchronization with the Stream backend.\n *\n * This includes downloading events since the last sync, updating the local DB,\n * and handling sync failures (e.g., if syncing beyond the allowed retention window).\n */\n private sync = async () => {\n if (!this.client?.user) {\n return;\n }\n try {\n const cids = await this.offlineDb.getAllChannelCids();\n // If there are no channels, then there is no need to sync.\n if (cids.length === 0) {\n return;\n }\n\n // TODO: We should not need our own user ID in the API, it can be inferred\n const lastSyncedAt = await this.offlineDb.getLastSyncedAt({\n userId: this.client.user.id,\n });\n\n if (lastSyncedAt) {\n const lastSyncedAtDate = new Date(lastSyncedAt);\n const nowDate = new Date();\n\n // Calculate the difference in days\n const diff = Math.floor(\n (nowDate.getTime() - lastSyncedAtDate.getTime()) / (1000 * 60 * 60 * 24),\n );\n\n if (diff > 30) {\n // stream backend will send an error if we try to sync after 30 days.\n // In that case reset the entire DB and start fresh.\n await this.offlineDb.resetDB();\n } else {\n const result = await this.client.sync(cids, lastSyncedAtDate.toISOString());\n const queryPromises = result.events.map((event) =>\n this.offlineDb.handleEvent({ event, execute: false }),\n );\n const queriesArray = await Promise.all(queryPromises);\n const queries = queriesArray.flat() as ExecuteBatchDBQueriesType;\n\n if (queries.length) {\n await this.offlineDb.executeSqlBatch(queries);\n }\n }\n }\n await this.offlineDb.upsertUserSyncStatus({\n userId: this.client.user.id,\n lastSyncedAt: new Date().toString(),\n });\n } catch (e) {\n console.log('An error has occurred while syncing the DB.', e);\n\n if (isAxiosError(e) && e.code === 'ECONNABORTED') {\n // If the sync was aborted due to timeout, we can simply return\n return;\n }\n\n const error = e as AxiosError<APIErrorResponse>;\n\n if (error.response?.data?.code === 23) {\n return;\n }\n\n // Error will be raised by the sync API if there are too many events.\n // In that case reset the entire DB and start fresh.\n // We avoid resetting the DB if the error is due to timeout.\n await this.offlineDb.resetDB();\n }\n };\n\n /**\n * Executes any tasks that were queued while offline and then performs a sync.\n */\n private syncAndExecutePendingTasks = async () => {\n await this.offlineDb.executePendingTasks();\n await this.sync();\n };\n}\n", "import type { APIErrorResponse, ChannelResponse, Event } from '../types';\n\nimport type {\n OfflineDBApi,\n OfflineDBState,\n PendingTask,\n PrepareBatchDBQueries,\n} from './types';\nimport { OfflineError } from './types';\nimport type { StreamChat } from '../client';\nimport type { AxiosError } from 'axios';\nimport { OfflineDBSyncManager } from './offline_sync_manager';\nimport { StateStore } from '../store';\nimport { runDetached } from '../utils';\n\n/**\n * Abstract base class for an offline database implementation used with StreamChat.\n *\n * Manages state and synchronization logic between the client and the offline database,\n * as well as contains the API providing core functionality for tracking and persisting\n * offline data.\n *\n * @abstract\n */\nexport abstract class AbstractOfflineDB implements OfflineDBApi {\n private client: StreamChat;\n public syncManager: OfflineDBSyncManager;\n public state: StateStore<OfflineDBState>;\n\n constructor({ client }: { client: StreamChat }) {\n this.client = client;\n this.syncManager = new OfflineDBSyncManager({ client, offlineDb: this });\n this.state = new StateStore<OfflineDBState>({\n initialized: false,\n userId: this.client.userID,\n });\n }\n\n /**\n * @abstract\n * Inserts a reaction into the DB.\n * Will write to:\n * - The reactions table with the new reaction\n * - The message table with the message containing the new reaction\n * - The users table with any users associated\n * Will return the prepared queries for delayed execution (even if they are\n * already executed).\n * @param {DBInsertReactionType} options\n * @returns {Promise<ExecuteBatchDBQueriesType>}\n */\n abstract insertReaction: OfflineDBApi['insertReaction'];\n\n /**\n * @abstract\n * Upserts the list of CIDs for a filter + sort query hash.\n * Will write to only the table containing the cids.\n * Will return the prepared queries for delayed execution (even if they are\n * already executed).\n * @param {DBUpsertCidsForQueryType} options\n * @returns {Promise<ExecuteBatchDBQueriesType>}\n */\n abstract upsertCidsForQuery: OfflineDBApi['upsertCidsForQuery'];\n\n /**\n * @abstract\n * Upserts the channels passed as an argument within the DB. Relies on\n * writing the properties we need from a ChannelResponse into the adequate\n * tables.\n * Will write to:\n * - The channels table with the channel data\n * - The messages table with each message associated\n * - The reactions table if the messages contain reactions\n * - The users table with all users associated\n * - The members table for membership and members\n * - The polls table for any messages that are polls\n * - The reads table for each user\n * Will return the prepared queries for delayed execution (even if they are\n * already executed).\n * @param {DBUpsertChannelsType} options\n * @returns {Promise<ExecuteBatchDBQueriesType>}\n */\n abstract upsertChannels: OfflineDBApi['upsertChannels'];\n\n /**\n * @abstract\n * Upserts the current active user's sync status.\n * Will only write to the sync status table.\n * Will return the prepared queries for delayed execution (even if they are\n * already executed).\n * @param {DBUpsertUserSyncStatusType} options\n * @returns {Promise<ExecuteBatchDBQueriesType>}\n */\n abstract upsertUserSyncStatus: OfflineDBApi['upsertUserSyncStatus'];\n\n /**\n * @abstract\n * Upserts the app settings for the current Stream App into the DB. It\n * is only intended to be run once per lifecycle of the app.\n * Will only write to the respective app settings table.\n * Will return the prepared queries for delayed execution (even if they are\n * already executed).\n * @param {DBUpsertAppSettingsType} options\n * @returns {Promise<ExecuteBatchDBQueriesType>}\n */\n abstract upsertAppSettings: OfflineDBApi['upsertAppSettings'];\n\n /**\n * @abstract\n * Upserts a poll fully in the DB.\n * Will write to the polls table. It should not update the message\n * associated due to how the poll state works.\n * Will return the prepared queries for delayed execution (even if they are\n * already executed).\n * @param {DBUpsertPollType} options\n * @returns {Promise<ExecuteBatchDBQueriesType>}\n */\n abstract upsertPoll: OfflineDBApi['upsertPoll'];\n\n /**\n * @abstract\n * Upserts only the channel.data for the provided channels in the DB.\n * Will only write to the channels table.\n * Will return the prepared queries for delayed execution (even if they are\n * already executed).\n * @param {DBUpsertChannelDataType} options\n * @returns {Promise<ExecuteBatchDBQueriesType>}\n */\n abstract upsertChannelData: OfflineDBApi['upsertChannelData'];\n\n /**\n * @abstract\n * Upserts the provided reads in the DB.\n * Will write to:\n * - The reads table\n * - The users table for each user associated with a read\n * Will return the prepared queries for delayed execution (even if they are\n * already executed).\n * @param {DBUpsertReadsType} options\n * @returns {Promise<ExecuteBatchDBQueriesType>}\n */\n abstract upsertReads: OfflineDBApi['upsertReads'];\n\n /**\n * @abstract\n * Upserts the messages in the DB.\n * Will write to:\n * - The messages table\n * - The reads table\n * - The polls table (if any messages contain polls)\n * - The reactions table (if any messages contain reactions)\n * - The users table\n * Will return the prepared queries for delayed execution (even if they are\n * already executed).\n * @param {DBUpsertMessagesType} options\n * @returns {Promise<ExecuteBatchDBQueriesType>}\n */\n abstract upsertMessages: OfflineDBApi['upsertMessages'];\n\n /**\n * @abstract\n * Upserts the members in the DB.\n * Will write to:\n * - The users table (for each user associated with a member)\n * - The members table\n * Will return the prepared queries for delayed execution (even if they are\n * already executed).\n * @param {DBUpsertMembersType} options\n * @returns {Promise<ExecuteBatchDBQueriesType>}\n */\n abstract upsertMembers: OfflineDBApi['upsertMembers'];\n\n /**\n * @abstract\n * Updates a reaction in the DB. Will update the DB the same way\n * a reaction.updated event would (it assumes enforce_unique is true\n * and removes all other reactions associated with the user.\n * Will write to the reactions table.\n * Will return the prepared queries for delayed execution (even if they are\n * already executed).\n * @param {DBUpdateReactionType} options\n * @returns {Promise<ExecuteBatchDBQueriesType>}\n */\n abstract updateReaction: OfflineDBApi['updateReaction'];\n\n /**\n * @abstract\n * Updates a single message in the DB. This is used as a faster\n * alternative to upsertMessages with more optimized queries.\n * Will write to the messages table.\n * Will return the prepared queries for delayed execution (even if they are\n * already executed).\n * @param {DBUpdateMessageType} options\n * @returns {Promise<ExecuteBatchDBQueriesType>}\n */\n abstract updateMessage: OfflineDBApi['updateMessage'];\n\n /**\n * @abstract\n * Fetches the provided draft from the DB. Should return as close to\n * the server side DraftResponse as possible.\n * @param {DBGetDraftType} options\n * @returns {Promise<DraftResponse | null>}\n */\n abstract getDraft: OfflineDBApi['getDraft'];\n /**\n * @abstract\n * Upserts a draft in the DB.\n * Will write to the draft table upserting the draft.\n * Will return the prepared queries for delayed execution (even if they are\n * already executed).\n * @param {DBUpsertDraftType} options\n * @returns {Promise<ExecuteBatchDBQueriesType>}\n */\n abstract upsertDraft: OfflineDBApi['upsertDraft'];\n /**\n * @abstract\n * Deletes a draft from the DB.\n * Will write to the draft table removing the draft.\n * Will return the prepared queries for delayed execution (even if they are\n * already executed).\n * @param {DBDeleteDraftType} options\n * @returns {Promise<ExecuteBatchDBQueriesType>}\n */\n abstract deleteDraft: OfflineDBApi['deleteDraft'];\n\n /**\n * @abstract\n * Fetches the provided channels from the DB and aggregates all data associated\n * with them in a single ChannelAPIResponse. The implementation itself is responsible\n * for aggregating and serialization of all of the data. Should return as close to\n * the server side ChannelAPIResponse as possible.\n * @param {DBGetChannelsType} options\n * @returns {Promise<Omit<ChannelAPIResponse, 'duration'>[] | null>}\n */\n abstract getChannels: OfflineDBApi['getChannels'];\n\n /**\n * @abstract\n * Fetches the channels from the DB that were the last known response to a filters & sort\n * hash as a query and aggregates all data associated with them in a single ChannelAPIResponse.\n * The implementation itself is responsible for aggregating and serialization of all of the data.\n * Should return as close to the server side ChannelAPIResponse as possible.\n * @param {DBGetChannelsForQueryType} options\n * @returns {Promise<Omit<ChannelAPIResponse, 'duration'>[] | null>}\n */\n abstract getChannelsForQuery: OfflineDBApi['getChannelsForQuery'];\n\n /**\n * @abstract\n * Will return a list of all available CIDs in the DB. The same can be achieved\n * by fetching all channels, however this is meant to be much faster as a query.\n * @returns {Promise<string[]>}\n */\n abstract getAllChannelCids: OfflineDBApi['getAllChannelCids'];\n\n /**\n * @abstract\n * Fetches the timestamp of the last sync of the DB.\n * @param {DBGetLastSyncedAtType} options\n * @returns {Promise<string | undefined>}\n */\n abstract getLastSyncedAt: OfflineDBApi['getLastSyncedAt'];\n\n /**\n * @abstract\n * Fetches all pending tasks from the DB. It will return them in an\n * ordered fashion by the time they were created.\n * @param {DBGetPendingTasksType} [conditions]\n * @returns {Promise<PendingTask[]>}\n */\n abstract getPendingTasks: OfflineDBApi['getPendingTasks'];\n\n /**\n * @abstract\n * Fetches the app settings stored in the DB. Is mainly meant to be used\n * only while offline and opening the application, as we only update the\n * app settings whenever they are fetched again so it has the potential to\n * be stale.\n * @param {DBGetAppSettingsType} options\n * @returns {Promise<AppSettingsAPIResponse | null>}\n */\n abstract getAppSettings: OfflineDBApi['getAppSettings'];\n\n /**\n * @abstract\n * Fetches reactions from the DB for a given filter & sort hash and\n * for a given message ID.\n * @param {DBGetReactionsType} options\n * @returns {Promise<ReactionResponse[] | null>}\n */\n abstract getReactions: OfflineDBApi['getReactions'];\n\n /**\n * @abstract\n * Executes multiple queries in a batched fashion. It will also be done\n * within a transaction.\n * @param {ExecuteBatchDBQueriesType} queries\n * @returns {Promise<unknown>}\n */\n abstract executeSqlBatch: OfflineDBApi['executeSqlBatch'];\n\n /**\n * @abstract\n * Adds a pending task to the pending tasks table. Can only be one of the\n * supported types of pending tasks, otherwise its execution will throw.\n * Will return the prepared queries for delayed execution (even if they are\n * already executed).\n * @param {PendingTask} task\n * @returns {Promise<() => Promise<void>>}\n */\n abstract addPendingTask: OfflineDBApi['addPendingTask'];\n\n /**\n * @abstract\n * Deletes a pending task from the DB, given its ID.\n * Will return the prepared queries for delayed execution (even if they are\n * already executed).\n * @param {DBDeletePendingTaskType} options\n * @returns {Promise<ExecuteBatchDBQueriesType>}\n */\n abstract deletePendingTask: OfflineDBApi['deletePendingTask'];\n\n /**\n * @abstract\n * Deletes a reaction from the DB.\n * Will write to the reactions table removing the reaction.\n * Will return the prepared queries for delayed execution (even if they are\n * already executed).\n * @param {DBDeleteReactionType} options\n * @returns {Promise<ExecuteBatchDBQueriesType>}\n */\n abstract deleteReaction: OfflineDBApi['deleteReaction'];\n\n /**\n * @abstract\n * Deletes a member from the DB.\n * Will only write to the members table.\n * Will return the prepared queries for delayed execution (even if they are\n * already executed).\n * @param {DBDeleteMemberType} options\n * @returns {Promise<ExecuteBatchDBQueriesType>}\n */\n abstract deleteMember: OfflineDBApi['deleteMember'];\n\n /**\n * @abstract\n * Deletes a channel from the DB.\n * It will also delete all other entities associated with the channel in\n * a cascading fashion (messages, reactions, members etc.).\n * Will return the prepared queries for delayed execution (even if they are\n * already executed).\n * @param {DBDeleteChannelType} options\n * @returns {Promise<ExecuteBatchDBQueriesType>}\n */\n abstract deleteChannel: OfflineDBApi['deleteChannel'];\n\n /**\n * @abstract\n * Deletes multiple messages for a given channel. Works as `channel.truncated` would.\n * Should remove entities primarily from the messages table and then from all associated\n * tables in a cascading fashion (reactions, polls etc.).\n * Will return the prepared queries for delayed execution (even if they are\n * already executed).\n * @param {DBDeleteMessagesForChannelType} options\n * @returns {Promise<ExecuteBatchDBQueriesType>}\n */\n abstract deleteMessagesForChannel: OfflineDBApi['deleteMessagesForChannel'];\n\n /**\n * @abstract\n * Deletes all pending tasks from the DB.\n * Will only update the pending tasks table.\n * Will return the prepared queries for delayed execution (even if they are\n * already executed).\n * @param {DBDropPendingTasksType} options\n * @returns {Promise<ExecuteBatchDBQueriesType>}\n */\n abstract dropPendingTasks: OfflineDBApi['dropPendingTasks'];\n\n /**\n * @abstract\n * Deletes a message from the DB.\n * All other entities associated with the message will also be deleted\n * in a cascading fashion (reactions, polls etc.).\n * Will return the prepared queries for delayed execution (even if they are\n * already executed).\n * @param {DBDeleteMessageType} options\n * @returns {Promise<ExecuteBatchDBQueriesType>}\n */\n abstract hardDeleteMessage: OfflineDBApi['hardDeleteMessage'];\n\n /**\n * @abstract\n * Updates a message with a deleted_at value in the DB.\n * Will only update the messages table, as the message is simply marked\n * as deleted and not removed from the DB.\n * Will return the prepared queries for delayed execution (even if they are\n * already executed).\n * @param {DBDeleteMessageType} options\n * @returns {Promise<ExecuteBatchDBQueriesType>}\n */\n abstract softDeleteMessage: OfflineDBApi['softDeleteMessage'];\n\n /**\n * @abstract\n * Drops all tables and reinitializes the connection to the DB.\n * @returns {Promise<unknown>}\n */\n abstract resetDB: OfflineDBApi['resetDB'];\n\n /**\n * @abstract\n * A utility query that checks whether a specific channel exists in the DB.\n * Technically the same as actually fetching that channel through other queries,\n * but much faster.\n * @param {DBChannelExistsType} options\n * @returns {Promise<boolean>}\n */\n abstract channelExists: OfflineDBApi['channelExists'];\n\n /**\n * @abstract\n * Initializes the DB (typically creating a simple file handle as a connection pointer for\n * SQLite and likely similar for other DBs).\n * @returns {Promise<boolean>}\n */\n abstract initializeDB: OfflineDBApi['initializeDB'];\n\n /**\n * Initializes the DB as well as its syncManager for a given userId.\n * It will update the DBs reactive state with initialization values.\n * @param userId - the user ID for which we want to initialize\n */\n public init = async (userId: string) => {\n try {\n if (!this.shouldInitialize(userId)) {\n // Note: We need this to return as changing the API is a breaking change.\n // This will change in the next major release.\n const initialized = await this.initializeDB();\n if (initialized) {\n await this.syncManager.init();\n this.state.partialNext({ initialized: true, userId });\n } else {\n this.state.partialNext({ initialized: false });\n }\n }\n } catch (error) {\n this.state.partialNext({ initialized: false, userId: undefined });\n console.log('Error Initializing DB:', error);\n }\n };\n\n /**\n * Checks whether the DB should be initialized or if it has been initialized already.\n * @param {string} userId - the user ID for which we want to check initialization\n */\n public shouldInitialize(userId: string): boolean {\n const { userId: userIdFromState, initialized } = this.state.getLatestValue();\n return userId === userIdFromState && initialized;\n }\n\n /**\n * A utility method used to execute a query in a detached manner. The callback\n * passed uses a reference to the DB itself and will handle errors gracefully\n * and silently. Only really meant to be used for write queries that need to\n * be run in synchronous functions.\n * @param queryCallback - a callback wrapping all query logic that is to be executed\n * @param method - a utility parameter used for proper logging (will make sure the method\n * is logged on failure)\n */\n public executeQuerySafely = <T>(\n queryCallback: (db: AbstractOfflineDB) => Promise<T>,\n { method }: { method: string },\n ) => {\n const { initialized } = this.state.getLatestValue();\n if (!initialized) {\n return;\n }\n runDetached(queryCallback(this), { context: `OfflineDB(${method})` });\n };\n\n /**\n * A utility method used to guard a certain DB query with the possible non-existance\n * of a channel inside of the DB. If the channel we want to guard against does not exist\n * in the DB yet, it will try to:\n *\n * 1. Use the channel from the WS event\n * 2. Use the channel from state\n *\n * and upsert the channels in the DB.\n *\n * If both fail, it will not execute the query as it would result in a foreign key constraint\n * error.\n *\n * @param event - the WS event we are trying to process\n * @param execute - whether to immediately execute the operation.\n * @param forceUpdate - whether to upsert the channel data anyway\n * @param createQueries - a callback function to creation of the queries that we want to execute\n */\n public queriesWithChannelGuard = async (\n {\n event,\n execute = true,\n forceUpdate = false,\n }: { event: Event; execute?: boolean; forceUpdate?: boolean },\n createQueries: (executeOverride?: boolean) => Promise<PrepareBatchDBQueries[]>,\n ) => {\n const channelFromEvent = event.channel;\n const cid = event.cid || channelFromEvent?.cid;\n const type = event.type;\n\n if (!cid) {\n return await createQueries(execute);\n }\n // We want to upsert the channel data if we either:\n // - Have forceUpdate set to true\n // - The channel does not yet exist in the DB\n // If a channel is not present in the db, we first fetch the channel data from the channel object.\n // This can happen for example when a message.new event is received for a channel that is not in the db due to a channel being hidden.\n const shouldUpsertChannelData = forceUpdate || !(await this.channelExists({ cid }));\n if (shouldUpsertChannelData) {\n let channelData = channelFromEvent;\n if (!channelData && event.channel_type && event.channel_id) {\n const channelFromState = this.client.channel(\n event.channel_type,\n event.channel_id,\n );\n if (channelFromState.initialized && !channelFromState.disconnected) {\n channelData = channelFromState.data as unknown as ChannelResponse;\n }\n }\n if (channelData) {\n const channelQuery = await this.upsertChannelData({\n channel: channelData,\n execute: false,\n });\n if (channelQuery) {\n const createdQueries = await createQueries(false);\n const newQueries = [...channelQuery, ...createdQueries];\n if (execute) {\n await this.executeSqlBatch(newQueries);\n }\n return newQueries;\n } else {\n console.warn(\n `Couldn't create channel queries on ${type} event for an initialized channel that is not in DB, skipping event`,\n { event },\n );\n return [];\n }\n } else {\n console.warn(\n `Received ${type} event for a non initialized channel that is not in DB, skipping event`,\n { event },\n );\n return [];\n }\n }\n return await createQueries(execute);\n };\n\n /**\n * Handles a message.new event. Will always use a channel guard for the inner queries\n * and it is going to make sure that both messages and reads are upserted. It will not\n * try to fetch the reads from the DB first and it will rely on channel.state to handle\n * the number of unreads.\n * @param event - the WS event we are trying to process\n * @param execute - whether to immediately execute the operation.\n */\n public handleNewMessage = async ({\n event,\n execute = true,\n }: {\n event: Event;\n execute?: boolean;\n }) => {\n const client = this.client;\n const { cid, message, user } = event;\n\n if (!message || (message.parent_id && !message.show_in_channel)) {\n return [];\n }\n\n const finalQueries = await this.queriesWithChannelGuard(\n { event, execute },\n async () => {\n let queries = await this.upsertMessages({\n execute: false,\n messages: [message],\n });\n if (cid && client.user && client.user.id !== user?.id) {\n const userId = client.user.id;\n const channel = client.activeChannels[cid];\n if (channel) {\n const ownReads = channel.state.read[userId];\n const unreadCount = channel.countUnread();\n const upsertReadsQueries = await this.upsertReads({\n cid,\n execute: false,\n reads: [\n {\n last_read: ownReads.last_read.toISOString() as string,\n last_read_message_id: ownReads.last_read_message_id,\n unread_messages: unreadCount,\n user: client.user,\n },\n ],\n });\n queries = [...queries, ...upsertReadsQueries];\n }\n }\n return queries;\n },\n );\n\n if (execute) {\n await this.executeSqlBatch(finalQueries);\n }\n\n return finalQueries;\n };\n\n /**\n * A handler for message deletion. It provides a channel guard and determines whether\n * it should hard delete or soft delete the message.\n * @param event - the WS event we are trying to process\n * @param execute - whether to immediately execute the operation.\n */\n public handleDeleteMessage = async ({\n event,\n execute = true,\n }: {\n event: Event;\n execute?: boolean;\n }) => {\n const { message, hard_delete = false } = event;\n\n if (message) {\n const deleteMethod = hard_delete ? this.hardDeleteMessage : this.softDeleteMessage;\n return await this.queriesWithChannelGuard(\n { event, execute },\n async (executeOverride) =>\n await deleteMethod({ id: message.id, execute: executeOverride }),\n );\n }\n\n return [];\n };\n\n /**\n * A utility method used for removing a message that has already failed from the\n * state as well as the DB. We want to drop all pending tasks and finally hard\n * delete the message from the DB.\n * @param messageId - the message id of the message we want to remove\n * @param execute - whether to immediately execute the operation.\n */\n public handleRemoveMessage = async ({\n messageId,\n execute = true,\n }: {\n messageId: string;\n execute?: boolean;\n }) => {\n const dropPendingTasksQueries = await this.dropPendingTasks({\n messageId,\n execute: false,\n });\n const hardDeleteMessageQueries = await this.hardDeleteMessage({\n id: messageId,\n execute: false,\n });\n const queries = [...dropPendingTasksQueries, ...hardDeleteMessageQueries];\n\n if (execute) {\n await this.executeSqlBatch(queries);\n }\n\n return queries;\n };\n\n /**\n * A utility method to handle read events. It will calculate the state of the reads if\n * present in the event, or optionally rely on the hard override in unreadMessages.\n * The unreadMessages argument is useful for cases where we know the exact number of unreads\n * (for example reading an entire channel), but `unread_messages` might not necessarily exist\n * in the event (or it exists with a stale value if we know what we want to ultimately update to).\n * @param event - the WS event we are trying to process\n * @param unreadMessages - an override of unread_messages that will be preferred when upserting reads\n * @param execute - whether to immediately execute the operation.\n */\n public handleRead = async ({\n event,\n unreadMessages,\n execute = true,\n }: {\n event: Event;\n unreadMessages?: number;\n execute?: boolean;\n }) => {\n const {\n received_at: last_read,\n last_read_message_id,\n unread_messages = 0,\n user,\n cid,\n } = event;\n\n const overriddenUnreadMessages = unreadMessages ?? unread_messages;\n\n if (user?.id && cid) {\n return await this.queriesWithChannelGuard({ event, execute }, (executeOverride) =>\n this.upsertReads({\n cid,\n execute: executeOverride,\n reads: [\n {\n last_read: last_read as string,\n last_read_message_id,\n unread_messages: overriddenUnreadMessages,\n user,\n },\n ],\n }),\n );\n }\n\n return [];\n };\n\n /**\n * A utility method used to handle member events. It guards the processing\n * of each event with a channel guard and also forces an update of member_count\n * for the respective channel if applicable.\n * @param event - the WS event we are trying to process\n * @param execute - whether to immediately execute the operation.\n */\n public handleMemberEvent = async ({\n event,\n execute = true,\n }: {\n event: Event;\n execute?: boolean;\n }) => {\n const { member, cid, type } = event;\n\n if (member && cid) {\n // we force update here so that member_count gets updated\n // TODO: Although this is more than fine for now, we should look into\n // changing this to be an actual update to the DB instead.\n return await this.queriesWithChannelGuard(\n { event, execute, forceUpdate: true },\n async (executeOverride) => {\n if (type === 'member.removed') {\n return await this.deleteMember({ member, cid, execute: executeOverride });\n }\n\n return await this.upsertMembers({\n cid,\n members: [member],\n execute: executeOverride,\n });\n },\n );\n }\n\n return [];\n };\n\n /**\n * A utility method used to handle message.updated events. It guards each\n * event handler within a channel guard.\n * @param event - the WS event we are trying to process\n * @param execute - whether to immediately execute the operation.\n */\n public handleMessageUpdatedEvent = async ({\n event,\n execute = true,\n }: {\n event: Event;\n execute?: boolean;\n }) => {\n const { message } = event;\n\n if (message && !message.parent_id) {\n return await this.queriesWithChannelGuard(\n { event, execute },\n async (executeOverride) =>\n await this.updateMessage({ message, execute: executeOverride }),\n );\n }\n\n return [];\n };\n\n /**\n * An event handler for channel.visible and channel.hidden events. We need a separate\n * handler because event.channel.hidden does not arrive with the baseline event, so a\n * simple upsertion is not enough.\n * It will update the hidden property of a channel to true if handling the `channel.hidden`\n * event and to false if handling `channel.visible`.\n * @param event - the WS event we are trying to process\n * @param execute - whether to immediately execute the operation.\n */\n public handleChannelVisibilityEvent = async ({\n event,\n execute = true,\n }: {\n event: Event;\n execute?: boolean;\n }) => {\n const { type, channel } = event;\n\n if (channel && type) {\n const hidden = type === 'channel.hidden';\n return await this.upsertChannelData({\n channel: { ...channel, hidden },\n execute,\n });\n }\n\n return [];\n };\n\n /**\n * A utility handler used to handle channel.truncated events. It handles both\n * removing all messages and relying on truncated_at as well. It will also upsert\n * reads adequately (and calculate the correct unread messages when truncating).\n * @param event - the WS event we are trying to process\n * @param execute - whether to immediately execute the operation.\n */\n public handleChannelTruncatedEvent = async ({\n event,\n execute = true,\n }: {\n event: Event;\n execute?: boolean;\n }) => {\n const { channel } = event;\n const ownUser = this.client.user;\n if (channel && ownUser) {\n const { cid, truncated_at } = channel;\n const truncateQueries = await this.deleteMessagesForChannel({\n cid,\n truncated_at,\n execute: false,\n });\n\n const userId = ownUser.id;\n const activeChannel = this.client.activeChannels[cid];\n const ownReads = activeChannel.state.read[userId];\n\n let unreadCount = 0;\n\n if (truncated_at) {\n const truncatedAt = new Date(truncated_at);\n unreadCount = activeChannel.countUnread(truncatedAt);\n }\n\n const upsertReadQueries = await this.upsertReads({\n cid,\n execute: false,\n reads: [\n {\n last_read: ownReads.last_read.toString() as string,\n last_read_message_id: ownReads.last_read_message_id,\n unread_messages: unreadCount,\n user: ownUser,\n },\n ],\n });\n\n const finalQueries = [...truncateQueries, ...upsertReadQueries];\n\n if (execute) {\n await this.executeSqlBatch(finalQueries);\n }\n\n return finalQueries;\n }\n\n return [];\n };\n\n /**\n * A utility handler for all reaction events. It wraps the inner queries\n * within a channel guard and maps them like so:\n * - reaction.new -> insertReaction\n * - reaction.updated -> updateReaction\n * - reaction.deleted -> deleteReaction\n * @param event - the WS event we are trying to process\n * @param execute - whether to immediately execute the operation.\n */\n public handleReactionEvent = async ({\n event,\n execute = true,\n }: {\n event: Event;\n execute?: boolean;\n }) => {\n const { type, message, reaction } = event;\n\n if (!(message && reaction)) {\n return [];\n }\n\n const getReactionMethod = (type: Event['type']) => {\n switch (type) {\n case 'reaction.new':\n return this.insertReaction;\n case 'reaction.deleted':\n return this.deleteReaction;\n case 'reaction.updated':\n return this.updateReaction;\n default:\n throw new Error(\n `You are trying to handle a non-reaction event (${type}) through the reaction DB api.`,\n );\n }\n };\n\n const reactionMethod = getReactionMethod(type);\n\n return await this.queriesWithChannelGuard({ event, execute }, (executeOverride) =>\n reactionMethod({ message, reaction, execute: executeOverride }),\n );\n };\n\n /**\n * A utility handler for all draft events:\n * - draft.updated -> updateDraft\n * - draft.deleted -> deleteDraft\n * @param event - the WS event we are trying to process\n * @param execute - whether to immediately execute the operation.\n */\n handleDraftEvent = async ({\n event,\n execute = true,\n }: {\n event: Event;\n execute?: boolean;\n }) => {\n const { cid, draft, type } = event;\n\n if (!draft) return [];\n\n if (type === 'draft.updated') {\n return await this.upsertDraft({\n draft,\n execute,\n });\n }\n\n if (type === 'draft.deleted') {\n if (!cid) return [];\n\n return await this.deleteDraft({\n cid,\n parent_id: draft.parent_id,\n execute,\n });\n }\n\n return [];\n };\n\n /**\n * A generic event handler that decides which DB API to invoke based on\n * event.type for all events we are currently handling. It is used to both\n * react on WS events as well as process the sync API events.\n * @param event - the WS event we are trying to process\n * @param execute - whether to immediately execute the operation.\n */\n public handleEvent = async ({\n event,\n execute = true,\n }: {\n event: Event;\n execute?: boolean;\n }) => {\n const { type, channel } = event;\n\n if (type.startsWith('reaction')) {\n return await this.handleReactionEvent({ event, execute });\n }\n\n if (type === 'message.new') {\n return await this.handleNewMessage({ event, execute });\n }\n\n if (type === 'message.deleted') {\n return await this.handleDeleteMessage({ event, execute });\n }\n\n if (type === 'message.updated' || type === 'message.undeleted') {\n return this.handleMessageUpdatedEvent({ event, execute });\n }\n\n if (type === 'message.read' || type === 'notification.mark_read') {\n return this.handleRead({ event, unreadMessages: 0, execute });\n }\n\n if (type === 'notification.mark_unread') {\n return this.handleRead({ event, execute });\n }\n\n if (type.startsWith('member.')) {\n return await this.handleMemberEvent({ event, execute });\n }\n\n if (type === 'channel.hidden' || type === 'channel.visible') {\n return await this.handleChannelVisibilityEvent({ event, execute });\n }\n\n if (type === 'draft.updated' || type === 'draft.deleted') {\n return await this.handleDraftEvent({ event, execute });\n }\n\n // Note: It is a bit counter-intuitive that we do not touch the messages in the\n // offline DB when receiving notification.message_new, however we do this\n // because we anyway cannot get the messages for a channel until we run\n // either channel.watch() or channel.query(...) to get them. So, when\n // receiving the event we only upsert the channel data and we leave the\n // rest of the entities to be updated whenever we actually start watching\n // or we at least query.\n if (\n (type === 'channel.updated' ||\n type === 'notification.message_new' ||\n type === 'notification.added_to_channel') &&\n channel\n ) {\n return await this.upsertChannelData({ channel, execute });\n }\n\n if (\n (type === 'channel.deleted' ||\n type === 'notification.channel_deleted' ||\n type === 'notification.removed_from_channel') &&\n channel\n ) {\n return await this.deleteChannel({ cid: channel.cid, execute });\n }\n\n if (type === 'channel.truncated') {\n return await this.handleChannelTruncatedEvent({ event, execute });\n }\n\n return [];\n };\n\n /**\n * A method used to enqueue a pending task if the execution of it fails.\n * It will try to do the following:\n *\n * 1. Execute the task immediately\n * 2. If this fails, checks if the failure was due to something valid for a pending task\n * 3. If it is, it will insert the task in the pending tasks table\n *\n * It will return the response from the execution if it succeeded.\n * @param task - the pending task we want to execute\n */\n public queueTask = async <T>({ task }: { task: PendingTask }): Promise<T> => {\n const attemptTaskExecution = async () => {\n if (!this.client.wsConnection?.isHealthy) {\n throw new OfflineError(\n 'Cannot execute task because the connection has been lost.',\n { type: 'connection:lost' },\n );\n }\n return (await this.executeTask({ task })) as T;\n };\n try {\n return await attemptTaskExecution();\n } catch (e) {\n if (!this.shouldSkipQueueingTask(e as AxiosError<APIErrorResponse>)) {\n await this.addPendingTask(task);\n }\n throw e;\n }\n };\n\n /**\n * A utility method that determines if a failed task should be added to the\n * queue based on its error.\n * Error code 4 - bad request data\n * Error code 17 - missing own_capabilities to execute the task\n * @param error\n */\n private shouldSkipQueueingTask = (error: AxiosError<APIErrorResponse>) =>\n error?.response?.data?.code === 4 || error?.response?.data?.code === 17;\n\n /**\n * Executes a task from the list of supported pending tasks. Currently supported pending tasks\n * are:\n * - Deleting a message\n * - Sending a reaction\n * - Removing a reaction\n * - Sending a message\n * It will throw if we try to execute a pending task that is not supported.\n * @param task - The task we want to execute\n * @param isPendingTask - a control value telling us if it's an actual pending task being executed\n * or delayed execution\n */\n private executeTask = async (\n { task }: { task: PendingTask },\n isPendingTask = false,\n ) => {\n if (task.type === 'delete-message') {\n return await this.client._deleteMessage(...task.payload);\n }\n\n const { channelType, channelId } = task;\n\n if (channelType && channelId) {\n const channel = this.client.channel(channelType, channelId);\n\n if (task.type === 'send-reaction') {\n return await channel._sendReaction(...task.payload);\n }\n\n if (task.type === 'delete-reaction') {\n return await channel._deleteReaction(...task.payload);\n }\n\n if (task.type === 'create-draft') {\n return await channel._createDraft(...task.payload);\n }\n\n if (task.type === 'delete-draft') {\n return await channel._deleteDraft(...task.payload);\n }\n\n if (task.type === 'send-message') {\n const newMessageResponse = await channel._sendMessage(...task.payload);\n const newMessage = newMessageResponse?.message;\n if (isPendingTask && newMessage) {\n if (newMessage?.parent_id) {\n this.client.threads.threadsById[newMessage.parent_id]?.upsertReplyLocally({\n message: newMessage,\n timestampChanged: true,\n });\n }\n channel.state.addMessageSorted(newMessage, true);\n }\n return newMessageResponse;\n }\n }\n\n throw new Error(\n `Tried to execute invalid pending task type (${task.type}) while synchronizing the database.`,\n );\n };\n\n /**\n * A utility method used to execute all pending tasks. As each task succeeds execution,\n * it is going to be removed from the DB. If the execution failed due to a valid reason\n * it is going to remove the pending task from the DB even if execution fails, otherwise\n * it will keep it for the next time we try to execute all pending taks.\n */\n public executePendingTasks = async () => {\n const queue = await this.getPendingTasks();\n for (const task of queue) {\n if (!task.id) {\n continue;\n }\n\n try {\n await this.executeTask(\n {\n task,\n },\n true,\n );\n } catch (e) {\n const error = e as AxiosError<APIErrorResponse>;\n if (!this.shouldSkipQueueingTask(error)) {\n // executing the pending task has failed, so keep it in the queue\n continue;\n }\n }\n\n await this.deletePendingTask({\n id: task.id,\n });\n }\n };\n}\n", "/**\n * RULES:\n *\n * 1. one loc-sharing message per channel per user\n * 2. live location is intended to be per device\n * but created_by_device_id has currently no checks,\n * and user can update the location from another device\n * thus making location sharing based on user and channel\n */\n\nimport { withCancellation } from './utils/concurrency';\nimport { StateStore } from './store';\nimport { WithSubscriptions } from './utils/WithSubscriptions';\nimport type { StreamChat } from './client';\nimport type { Unsubscribe } from './store';\nimport type {\n EventTypes,\n MessageResponse,\n SharedLiveLocationResponse,\n SharedLocationResponse,\n} from './types';\nimport type { Coords } from './messageComposer';\n\nexport type WatchLocationHandler = (value: Coords) => void;\nexport type WatchLocation = (handler: WatchLocationHandler) => Unsubscribe;\ntype DeviceIdGenerator = () => string;\ntype MessageId = string;\n\nexport type ScheduledLiveLocationSharing = SharedLiveLocationResponse & {\n stopSharingTimeout: ReturnType<typeof setTimeout> | null;\n};\n\nexport type LiveLocationManagerState = {\n ready: boolean;\n messages: Map<MessageId, ScheduledLiveLocationSharing>;\n};\n\nconst isExpiredLocation = (location: SharedLiveLocationResponse) => {\n const endTimeTimestamp = new Date(location.end_at).getTime();\n\n return endTimeTimestamp < Date.now();\n};\n\nfunction isValidLiveLocationMessage(\n message?: MessageResponse,\n): message is MessageResponse & { shared_location: SharedLiveLocationResponse } {\n if (!message || message.type === 'deleted' || !message.shared_location?.end_at)\n return false;\n\n return !isExpiredLocation(message.shared_location as SharedLiveLocationResponse);\n}\n\nexport type LiveLocationManagerConstructorParameters = {\n client: StreamChat;\n getDeviceId: DeviceIdGenerator;\n watchLocation: WatchLocation;\n};\n\n// Hard-coded minimal throttle timeout\nexport const UPDATE_LIVE_LOCATION_REQUEST_MIN_THROTTLE_TIMEOUT = 3000;\n\nexport class LiveLocationManager extends WithSubscriptions {\n public state: StateStore<LiveLocationManagerState>;\n private client: StreamChat;\n private getDeviceId: DeviceIdGenerator;\n private _deviceId: string;\n private watchLocation: WatchLocation;\n\n static symbol = Symbol(LiveLocationManager.name);\n\n constructor({\n client,\n getDeviceId,\n watchLocation,\n }: LiveLocationManagerConstructorParameters) {\n if (!client.userID) {\n throw new Error('Live-location sharing is reserved for client-side use only');\n }\n\n super();\n\n this.client = client;\n this.state = new StateStore<LiveLocationManagerState>({\n messages: new Map(),\n ready: false,\n });\n this._deviceId = getDeviceId();\n this.getDeviceId = getDeviceId;\n this.watchLocation = watchLocation;\n }\n\n public async init() {\n await this.assureStateInit();\n this.registerSubscriptions();\n }\n\n public registerSubscriptions = () => {\n this.incrementRefCount();\n if (this.hasSubscriptions) return;\n\n this.addUnsubscribeFunction(this.subscribeLiveLocationSharingUpdates());\n this.addUnsubscribeFunction(this.subscribeTargetMessagesChange());\n };\n\n public unregisterSubscriptions = () => super.unregisterSubscriptions();\n\n get messages() {\n return this.state.getLatestValue().messages;\n }\n\n get stateIsReady() {\n return this.state.getLatestValue().ready;\n }\n\n get deviceId() {\n if (!this._deviceId) {\n this._deviceId = this.getDeviceId();\n }\n return this._deviceId;\n }\n\n private async assureStateInit() {\n if (this.stateIsReady) return;\n const { active_live_locations } = await this.client.getSharedLocations();\n this.state.next({\n messages: new Map(\n active_live_locations\n .filter((location) => !isExpiredLocation(location))\n .map((location) => [\n location.message_id,\n {\n ...location,\n stopSharingTimeout: setTimeout(\n () => {\n this.unregisterMessages([location.message_id]);\n },\n new Date(location.end_at).getTime() - Date.now(),\n ),\n },\n ]),\n ),\n ready: true,\n });\n }\n\n private subscribeTargetMessagesChange() {\n let unsubscribeWatchLocation: null | (() => void) = null;\n\n // Subscribe to location updates only if there are relevant messages to\n // update, no need for the location watcher to be active/instantiated otherwise\n const unsubscribe = this.state.subscribeWithSelector(\n ({ messages }) => ({ messages }),\n ({ messages }) => {\n if (!messages.size) {\n unsubscribeWatchLocation?.();\n unsubscribeWatchLocation = null;\n } else if (messages.size && !unsubscribeWatchLocation) {\n unsubscribeWatchLocation = this.subscribeWatchLocation();\n }\n },\n );\n\n return () => {\n unsubscribe();\n unsubscribeWatchLocation?.();\n };\n }\n\n private subscribeWatchLocation() {\n let nextAllowedUpdateCallTimestamp = Date.now();\n\n const unsubscribe = this.watchLocation(({ latitude, longitude }) => {\n // Integrators can adjust the update interval by supplying custom watchLocation subscription,\n // but the minimal timeout still has to be set as a failsafe (to prevent rate-limitting)\n if (Date.now() < nextAllowedUpdateCallTimestamp) return;\n\n nextAllowedUpdateCallTimestamp =\n Date.now() + UPDATE_LIVE_LOCATION_REQUEST_MIN_THROTTLE_TIMEOUT;\n\n withCancellation(LiveLocationManager.symbol, async () => {\n const promises: Promise<SharedLocationResponse>[] = [];\n await this.assureStateInit();\n const expiredLocations: string[] = [];\n\n for (const [messageId, location] of this.messages) {\n if (isExpiredLocation(location)) {\n expiredLocations.push(location.message_id);\n continue;\n }\n if (location.latitude === latitude && location.longitude === longitude)\n continue;\n const promise = this.client.updateLocation({\n created_by_device_id: location.created_by_device_id,\n message_id: messageId,\n latitude,\n longitude,\n });\n\n promises.push(promise);\n }\n this.unregisterMessages(expiredLocations);\n if (promises.length > 0) {\n await Promise.allSettled(promises);\n }\n // TODO: handle values (remove failed - based on specific error code), keep re-trying others\n });\n });\n\n return unsubscribe;\n }\n\n private subscribeLiveLocationSharingUpdates() {\n /**\n * Both message.updated & live_location_sharing.stopped get emitted when message gets an\n * update, live_location_sharing.stopped gets emitted only locally and only if the update goes\n * through, it's a failsafe for when channel is no longer being watched for whatever reason\n */\n const subscriptions = [\n ...(\n [\n 'live_location_sharing.started',\n 'message.updated',\n 'message.deleted',\n ] as EventTypes[]\n ).map((eventType) =>\n this.client.on(eventType, (event) => {\n if (!event.message) return;\n\n if (event.type === 'live_location_sharing.started') {\n this.registerMessage(event.message);\n } else if (event.type === 'message.updated') {\n const isRegistered = this.messages.has(event.message.id);\n if (isRegistered && !isValidLiveLocationMessage(event.message)) {\n this.unregisterMessages([event.message.id]);\n }\n this.registerMessage(event.message);\n } else {\n this.unregisterMessages([event.message.id]);\n }\n }),\n ),\n this.client.on('live_location_sharing.stopped', (event) => {\n if (!event.live_location) return;\n\n this.unregisterMessages([event.live_location?.message_id]);\n }),\n ];\n\n return () => subscriptions.forEach((subscription) => subscription.unsubscribe());\n }\n\n private registerMessage(message: MessageResponse) {\n if (\n !this.client.userID ||\n message?.user?.id !== this.client.userID ||\n !isValidLiveLocationMessage(message)\n )\n return;\n\n this.state.next((currentValue) => {\n const messages = new Map(currentValue.messages);\n messages.set(message.id, {\n ...message.shared_location,\n stopSharingTimeout: setTimeout(\n () => {\n this.unregisterMessages([message.id]);\n },\n new Date(message.shared_location.end_at).getTime() - Date.now(),\n ),\n });\n return {\n ...currentValue,\n messages,\n };\n });\n }\n\n private unregisterMessages(messageIds: string[]) {\n const messages = this.messages;\n const removedMessages = new Set(messageIds);\n const newMessages = new Map(\n Array.from(messages).filter(([messageId, location]) => {\n if (removedMessages.has(messageId) && location.stopSharingTimeout) {\n clearTimeout(location.stopSharingTimeout);\n location.stopSharingTimeout = null;\n }\n return !removedMessages.has(messageId);\n }),\n );\n\n if (newMessages.size === messages.size) return;\n\n this.state.partialNext({\n messages: newMessages,\n });\n }\n}\n", "type Dispose<K, T> = (key: K, value: T) => void;\n/**\n * A cache that stores a fixed number of values in a queue.\n * The most recently added or retrieved value is kept at the front of the queue.\n * @template K - The type of the keys.\n * @template T - The type of the values.\n */\nexport class FixedSizeQueueCache<K, T> {\n private keys: Array<K>;\n private size: number;\n private map: Map<K, T>;\n private dispose: Dispose<K, T> | null;\n\n constructor(size: number, options?: { dispose: (key: K, value: T) => void }) {\n if (!size) throw new Error('Size must be greater than 0');\n this.keys = [];\n this.size = size;\n this.map = new Map();\n this.dispose = options?.dispose ?? null;\n }\n\n /**\n * Adds a new or moves the existing reference to the front of the queue\n * @param key\n * @param value\n */\n add(key: K, value: T) {\n const index = this.keys.indexOf(key);\n\n if (index > -1) {\n this.keys.splice(this.keys.indexOf(key), 1);\n } else if (this.keys.length >= this.size) {\n const itemKey = this.keys.shift();\n\n if (itemKey) {\n const item = this.peek(itemKey);\n\n if (item) {\n this.dispose?.(itemKey, item);\n }\n\n this.map.delete(itemKey);\n }\n }\n\n this.keys.push(key);\n this.map.set(key, value);\n }\n\n /**\n * Retrieves the value by key.\n * @param key\n */\n peek(key: K) {\n const value = this.map.get(key);\n\n return value;\n }\n\n /**\n * Retrieves the value and moves it to the front of the queue.\n * @param key\n */\n get(key: K) {\n const foundItem = this.peek(key);\n\n if (foundItem && this.keys.indexOf(key) !== this.size - 1) {\n this.keys.splice(this.keys.indexOf(key), 1);\n this.keys.push(key);\n }\n\n return foundItem;\n }\n}\n"],
5
+ "mappings": "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",
6
+ "names": ["import_axios", "FormData", "user", "result", "pairKey", "target", "source", "result", "initState", "LinkPreviewStatus", "initState", "initState", "Product", "VotingVisibility", "levenshtein", "DEFAULT_OPTIONS", "initState", "text", "initState", "axios", "isWSFailure", "WebSocket", "jwt", "crypto", "import_axios", "axios", "unreadThreadCount", "poll", "oneMinute", "oneHour", "oneDay", "isString", "channel", "https", "axios", "import_axios", "type"]
7
+ }