import { AddMembersModel, ChatMemberDTO, ConversationItem, GroupPermission, HistoryMessageParam, HistoryMessageResponse, KickGroupMemberParams, LiveMessageParam, MarkConversationReadParam, MessageItem, MuteMembersParams, PageParam, PushChatMessage, ReqConversationListParam, ReqPageParam, ReqConversationQueryTypesParam, Request, ServerResponse, UpdateGroupMemberPermission, UpdateGroupPermission, ContactType, EditeContactTagDTO, AllocationContactTagDTO, GetFileByTypeParams } from '../types/entity'; import type { LoginParams, UploadFileParams } from '../types/params'; import { RequestApi } from '../constant/api'; import Emitter from '../utils/emitter'; import { ConnectionProtocol, GroupType, ConversationQueryType } from '../types/enum'; import { HttpMethod } from '../utils/request'; import { IConnectionClient } from '../utils/ConnectionClientFactory'; import { UserService } from './user'; import { GroupService } from './group'; import { MessageService } from './message'; import { ConversationService } from './conversation'; import { ContactService } from './contact'; interface SDKConfig { username?: string; token?: string; appKey?: string; apiAddr?: string; wsAddr?: string; ossApiAddr?: string; debug: boolean; isLive: boolean; anonLogin?: boolean; /** login() 传入,用于初始化/恢复会话缓存与拉首屏会话列表 */ conversationQueryTypes?: ConversationQueryType[]; connectTimeout?: number; maxRetries?: number; useProtobuf?: boolean; protocol?: ConnectionProtocol; } interface SDKOptions { debug?: boolean; isLive?: boolean; apiAddr?: string; wsAddr?: string; ossApiAddr?: string; appKey?: string; token?: string; connectTimeout?: number; maxRetries?: number; useProtobuf?: boolean; protocol?: ConnectionProtocol; } /** * SIMSDK主类 - 实时通信SDK的入口点 */ declare class SIMSDK extends Emitter { private config; private internalState; private cacheManager; private connectionClient?; private readonly serviceManager; private lastUnauthorizedTime; private readonly UNAUTHORIZED_THROTTLE_MS; private conversationUpdateTimer; private readonly CONVERSATION_UPDATE_THROTTLE_MS; private pendingConversationUpdateQueryTypes; private lastConversationUpdateTime; private isPageVisible; private pageVisibilityHandler; private readonly PAGE_HIDDEN_STOP_DELAY_MS; private pageHiddenTimer; private isActuallyHidden; private readonly PAGE_VISIBLE_STABLE_MS; private pageVisibleStableTimer; /** * 创建SIMSDK实例 * @param debug 是否启用调试模式 */ constructor(debug?: boolean); /** * 初始化页面可见性检测 * 用于控制后台时不触发事件,避免积压 */ private initPageVisibilityDetection; /** * 处理页面变为不可见 */ private handlePageHidden; /** * 处理页面变为可见 */ private handlePageVisible; /** * 清理页面可见性检测 */ private cleanupPageVisibilityDetection; /** * 清理和释放资源 */ destroy(): void; /** * 配置SDK * @param options SDK配置选项 */ configure: (options: SDKOptions) => void; /** * 获取指定服务实例 * @param name 服务名称 * @returns 服务实例 */ private getService; /** * 消息服务访问器 */ get message(): MessageService; /** * 会话服务访问器 */ get conversation(): ConversationService; /** * 群组服务访问器 */ get group(): GroupService; /** * 用户服务访问器 */ get user(): UserService; /** * 联系人服务访问器 */ get contact(): ContactService; /** * 获取用户名 */ get username(): string | undefined; /** * 获取配置 */ get getConfig(): SDKConfig | undefined; /** * 获取连接客户端实例 * @returns 连接客户端实例(如果已连接),否则返回 undefined */ get getConnectionClient(): IConnectionClient | undefined; /** * 检查是否已连接 * @returns 是否已连接 */ isConnected(): boolean; /** * 检查是否已登录 * @returns 是否已登录 */ isLoggedIn(): boolean; /** * 发送请求到服务器 * @param requestObj 请求对象 * @returns 请求响应Promise */ sendRequest: (requestObj: Request) => Promise>; /** * 带节流控制的401错误处理 * @param url 请求的URL */ private handleUnauthorizedWithThrottle; /** * 处理未授权错误 * @param url 请求的URL */ private handleUnauthorized; /** * 记录请求日志 * @param requestObj 请求对象 */ private logRequest; /** * 创建带参数的请求函数 * @param reqFuncName 请求API名称 * @param method HTTP方法 * @returns 请求函数 */ createRequestFunction: | undefined, ResType = unknown>(reqFuncName: RequestApi, method: HttpMethod) => (params: ReqType) => Promise>; /** * 创建无参数的请求函数 * @param reqFuncName 请求API名称 * @param method HTTP方法 * @returns 请求函数 */ createRequestFunctionWithoutParams: (reqFuncName: RequestApi, method: HttpMethod) => () => Promise>; /** * 处理 Pong 消息 * @param pongMessage pong 消息数据 */ private handlePongMessage; /** 文档约定:首字节 0x01=Protobuf,0x7D=PING,0x7E=PONG */ private static readonly BINARY_MSG_TYPE; /** * 处理SSE消息 - 支持 protobuf(与 FRONTEND_PROTOBUF_PARSING_GUIDE_WEB.md 一致) * @param response SSE/WebSocket 响应:JSON 对象 或 二进制(Uint8Array/ArrayBuffer/Base64) */ private handleMessage; /** * 是否为二进制消息(仅按数据类型判断,不依赖 useProtobuf 把对象当 protobuf) */ private isBinaryMessage; /** * 将二进制入参统一为 Uint8Array(用于首字节分发与解析) */ private normalizeToBinaryBuffer; /** * 判断是否是 Base64 字符串 * @param str 字符串 * @returns 是否是 Base64 格式 */ private isBase64String; /** * 将 proto GroupChat 转为 MessageItem,与 JSON 路径共用缓存与 emit */ private protoGroupChatToMessageItem; /** * 处理 protobuf 格式的消息:解析后与 JSON 分支触发相同的 emit(OnReceiveMessages / OnReceiveSystemMessage / OnReceiveSubscribeMessage 等) * @param response protobuf 响应(Uint8Array 或 Base64 字符串,首字节 0x01 为 BYTE_MESSAGE) */ private handleProtobufMessage; /** * 处理 JSON 格式的消息(原有逻辑) * @param response JSON 响应数据 */ private handleJsonMessage; /** * 处理重连成功事件 */ private handleReconnectSuccess; /** * 处理连接关闭事件 */ private handleConnectionClosed; /** 单个 queryType:发出 OnConversationListUpdated */ private emitConversationListUpdatedForQueryType; /** 多个 queryType:按顺序各发一次(非法项由 ForQueryType 内跳过) */ private emitConversationListUpdatedForQueryTypes; /** 该 groupId 涉及的所有 queryType 各触发一次列表更新(多 Tab 同步) */ private emitConversationListUpdatedForGroup; /** * 系统消息到达后:将单条 payload 视为 GroupEventPayload,同步可能受影响的本地会话缓存。 * (与 OnReceiveSystemMessage 并行;若连接层一次下发多条,上层需先拆成多次调用或在此扩展为遍历。) */ private handleSystemMessageForConversationCache; /** * 按群事件 type 处理本地缓存。当前仅 GROUP_MEMBER_EVENT_TYPE_SUPPORT_UPDATE(16): * content 内为 SupportChatTransferPayload 的 JSON,用于更新会话上的接入客服 id/昵称。 */ private handleGroupEvent; /** * 处理连接达到最大限制 */ private handleMaxRetriesReached; /** * 处理连接状态变化 */ private handleConnectionChange; /** * 登录到服务器 * @param params 登录参数 (只需要username和token) * @returns 登录结果Promise * @remarks 必须在调用login前先调用configure方法设置appKey和apiAddr配置。 */ login: (params: LoginParams) => Promise; /** * 登出 * @returns 登出结果Promise */ logout: () => Promise>; /** * 获取聊天对象的信息 * @param chatId 被查询人的信息(app用户id) * @param parent 是否查询上级信息(可选) * @returns 聊天对象信息Promise */ getChatMember: (chatId: number, parent?: boolean) => Promise>; /** * 初始化会话列表缓存 * @private */ private initializeConversationCache; /** * 获取会话列表 * @param params 分页参数。queryType 必填:0 非客服(私聊、频道等)沿用原分页逻辑(第二页起不强制 score);3/4/5/6 为游标分页,第一页不传 score,第二页起必须传 score。 * @returns Promise>> */ getConversations: (params: ReqConversationListParam) => Promise>>; /** * 获取会话列表(多 queryTypes) * * 新逻辑: * - queryTypes 为逗号分隔字符串,例如:'5,7' * - 仅支持第一页,不再支持 score / 游标分页 * - 返回格式:Map */ getConversationByQueryTypes: (params: ReqConversationQueryTypesParam) => Promise>>; /** * 内部上传文件方法(两步:先拉取阿里云 OSS 上传地址,再 PUT 到 OSS) * @param file 要上传的文件 * @param groupId 所属群组 ID,用于标识上传的文件归属 * @param ext 传给上传凭证接口的 ext 参数(如 `_dx`);最终文件名由服务端根据 filename + ext 拼接(如 `2.png` → `2_dx.png`) * @returns 上传结果,包括原图地址和缩略图地址,或错误信息 */ private internalUploadFile; /** * 上传文件 * @param params.file 文件 * @param params.ext 上传凭证 ext 参数,如 `_dx`(服务端将 `2.png` 处理为 `2_dx.png`) * @param groupId 群组 ID */ uploadFile: ({ file, ext }: UploadFileParams, groupId: number) => Promise>; /** * 监听单条消息 * @param callback 消息回调函数 * @returns 取消订阅函数 */ onMessage(callback: (message: MessageItem) => void): () => void; /** * 监听多条消息 * @param callback 消息回调函数 * @returns 取消订阅函数 */ onMessages(callback: (messages: MessageItem[]) => void): () => void; /** * 监听连接状态变化 * @param callback 状态变化回调 * @returns 取消订阅函数 */ onConnectionChange(callback: (isConnected: boolean) => void): () => void; /** * 监听被踢下线事件 * @param callback 回调函数 * @returns 取消订阅函数 */ onKickedOffline(callback: () => void): () => void; /** * 发送文本消息 * @param text 文本内容 * @param to 接收者用户名或群组ID * @param groupType 会话类型(群聊或私聊) * @param params 附加消息参数(MessageItem 类型的部分属性,排除 text 字段) * @returns Promise,返回服务器响应的消息列表 */ sendTextMessage: (text: string, to: string, groupType: GroupType, params?: Partial>) => Promise>; /** * 发送图片消息 * @param link 图片链接 * @param snapshot 图片缩略图(base64) * @param to 接收者用户名或群组ID * @param groupType 会话类型 * @param params 附加消息参数(排除 link 和 snapshot 字段) * @returns Promise,返回服务器响应的消息列表 */ sendImageMessage: (link: string, snapshot: string, to: string, groupType: GroupType, params?: Partial>) => Promise>; /** * 发送文件消息 * @param fileUrl 文件链接 * @param to 接收者用户名或群组ID * @param groupType 会话类型 * @param params 附加消息参数(排除 link 字段) * @returns Promise,返回服务器响应的消息列表 */ sendFileMessage: (fileUrl: string, to: string, groupType: GroupType, params?: Partial>) => Promise>; /** * 发送音频消息 * @param audioUrl 音频链接 * @param to 接收者用户名或群组ID * @param groupType 会话类型 * @param params 附加消息参数(排除 link 字段) * @returns Promise,返回服务器响应的消息列表 */ sendAudioMessage: (audioUrl: string, to: string, groupType: GroupType, params?: Partial>) => Promise>; /** * 发送视频消息 * @param videoUrl 视频链接 * @param to 接收者用户名或群组ID * @param groupType 会话类型 * @param params 附加消息参数(排除 link 字段) * @returns Promise,返回服务器响应的消息列表 */ sendVideoMessage: (videoUrl: string, to: string, groupType: GroupType, params?: Partial>) => Promise>; /** * 发送超链接消息 * @param linkUrl 超链接地址 * @param to 接收者用户名或群组ID * @param groupType 会话类型 * @param params 附加消息参数(排除 text 字段) * @returns Promise,返回服务器响应的消息列表 */ sendLinkMessage: (linkUrl: string, to: string, groupType: GroupType, params?: Partial>) => Promise>; /** * 发送 Gif 动图消息 * @param gifUrl gif 图片链接 * @param to 接收者用户名或群组ID * @param groupType 会话类型 * @param params 附加消息参数(排除 link 字段) * @returns Promise,返回服务器响应的消息列表 */ sendGifMessage: (gifUrl: string, to: string, groupType: GroupType, params?: Partial>) => Promise>; /** * 发送操作类型消息(如系统提示、操作反馈等) * @param optionText 操作文本内容 * @param to 接收者用户名或群组ID * @param groupType 会话类型 * @param params 附加消息参数(排除 text 字段) * @returns Promise,返回服务器响应的消息列表 */ sendOptionMessage: (optionText: string, to: string, groupType: GroupType, params?: Partial>) => Promise>; /** * 发送 Emoji 表情消息 * @param emoji Emoji 内容(如 😂) * @param to 接收者用户名或群组ID * @param groupType 会话类型 * @param params 附加消息参数(排除 text 字段) * @returns Promise,返回服务器响应的消息列表 */ sendEmojiMessage: (emoji: string, to: string, groupType: GroupType, params?: Partial>) => Promise>; /** * 发送自定义消息(前端/业务自定义格式) * @param customText 自定义内容(如 json 字符串) * @param to 接收者用户名或群组ID * @param groupType 会话类型 * @param params 附加消息参数(排除 text 字段) * @returns Promise,返回服务器响应的消息列表 */ sendCustomMessage: (customText: string, to: string, groupType: GroupType, params?: Partial>) => Promise>; /** * 获取历史消息列表 * @param params * @returns 历史消息 */ getHistoryMessageList: (params: HistoryMessageParam) => Promise>; /** * 获取直播消息列表 * @param params * @returns 历史消息 */ getLiveMessageList: (params: LiveMessageParam) => Promise>; /** * 客服消息预发送 * @param params 客服消息预发送参数 * @returns Promise */ prePushCustomerMessage: (params: PushChatMessage) => Promise; /** * 获取群组信息 * @param groupId 群组ID * @returns 群组信息 */ getGroupInfo: (groupId: number) => Promise>; /** * 获取群组成员列表 * @param params 包含群组ID和可选分页参数的对象 * @returns 群组成员信息 */ getGroupMembers: (params: { groupId: number; } & Partial) => Promise>; /** * 进群 * @param groupId 包含群组ID * @returns 进群状态 */ joinGroup: (groupId: number) => Promise>; /** * 退群 * @param groupId 包含群组ID * @returns 退群状态 */ leftGroup: (groupId: number) => Promise>; /** * 检测是否可以进群 * @param groupId 包含群组ID * @returns 是否可以进群状态 */ checkGroupBlock: (groupId: number) => Promise>; /** * 获取我的群权限 * @param groupId 包含群组ID * @returns 进群状态 */ getMyGroupPermission: (groupId: number) => Promise>; /** * 获取群权限 * @param groupId 包含群组ID * @returns 进群状态 */ getGroupPermission: (groupId: number) => Promise>; /** * 获取群成员 * @param groupId 包含群组ID * @returns 进群状态 */ getGroupMember: (groupId: number) => Promise; /** * 获取群成员权限 * @param groupId 包含群组ID * @param userId 包含用户ID * @returns 进群状态 */ getGroupMemberPermission: (groupId: number, userId: number) => Promise>; /** * 更新群权限(管理员使用) * @param params * @returns Promise */ updateGroupPermission: (params: UpdateGroupPermission) => Promise; /** * * @param params */ kickGroupMember: (params: KickGroupMemberParams) => Promise; /** * * @param params */ muteMembers: (params: MuteMembersParams) => Promise; /** * 更新群用户权限(管理员使用) * @param params * @returns Promise */ updateGroupMemberPermission: (params: UpdateGroupMemberPermission) => Promise; /** * 修改群名称 * @param groupId 包含 groupId * @param name 包含 name * @param avatar 包含 avatar * @returns Promise */ editGroupName: (groupId: number, name: string, avatar: string) => Promise; /** * 修改群简介/公告 * @param groupId 包含 groupId * @param notification 包含 notification * @returns Promise */ editNotification: (groupId: number, notification: string) => Promise; /** * 修改群自定义信息 * @param groupId 包含 groupId * @param customer 包含 customer * @returns Promise */ editGroupCustomer: (groupId: number, customer: string) => Promise; /** * 设置群管理员 * @param groupId 群 ID * @param username 用户名 * @returns Promise */ addAdmin: (groupId: number, username: number) => Promise; /** * 删除群管理员 * @param groupId 群 ID * @param username 用户名 * @returns Promise */ deleteAdmin: (groupId: number, username: number) => Promise; /** * 置顶消息 * @param groupId 群 ID * @param messageId 消息 ID * @param type 类型(0:取消置顶,1:置顶) * @returns Promise */ pin: (groupId: number, messageId: number, type: number) => Promise; /** * 群禁言 / 解除禁言 * @param groupId 群 ID * @param type 类型(0:禁言,1:解除禁言) * @returns Promise */ muteGroup: (groupId: number, type: number) => Promise; /** * 群成员禁言 / 解除禁言 * @param groupId 群 ID * @param username 用户名 * @param type 类型(0:禁言,1:解除禁言) * @returns Promise */ muteMember: (groupId: number, username: number, type: number) => Promise; /** * 批量添加群成员 * @param params 批量添加群成员参数 * @returns Promise */ addGroupMembers: (params: AddMembersModel) => Promise; /** * 获取群文件 * @param params 获取群文件参数 * @returns Promise */ getFileByType: (params: GetFileByTypeParams) => Promise; /** * 群置顶 * @param groupId 群组ID * @param type 0:添加 1:删除 * @returns Promise */ pinChat: (groupId: number, type: number) => Promise; /** * 解散群(只有群主才有权限) * @param groupId 群组ID * @returns Promise */ dissolveGroup: (groupId: number) => Promise; /** * 设置会话已读 * @param params 会话已读参数 * @returns 群组信息 */ markConversationRead: (params: MarkConversationReadParam) => Promise; /** * 标记最后一条已读信息 * @param groupId 群组ID * @param msgId 消息ID * @returns Promise */ markLastRead: (groupId: number, msgId: number) => Promise; /** * 更新最后删除游标(GET `/chat/conversation/lastDelete?groupId=&msgId=`,与 markLastRead 入参相同) */ markLastDelete: (groupId: number, msgId: number) => Promise; /** * 本地标记最后一条已读信息 * 用于用户发送消息后,同步本地已读状态(服务端已自动处理) * @param groupId 群组ID * @param msgId 消息ID * @returns void */ markLastReadLocal: (groupId: number, msgId: number) => void; /** * 置顶/取消置顶会话 * @param groupId 群组ID * @param isTop 0: 取消置顶, 1: 置顶(默认为1) * @returns Promise */ pinConversation: (groupId: number, isTop?: number) => Promise; /** * 静音/取消静音会话 * @param groupId 群组ID * @param mute 0: 取消静音, 1: 设置静音(默认为1) * @returns Promise */ muteConversation: (groupId: number, mute?: number) => Promise; /** * 获取渠道会话列表(客服专用) * @param params 分页参数 * @returns 渠道会话列表Promise */ getChannels: (params: ReqPageParam) => Promise>>; /** * 清除指定会话的未读数 * @param conversationId */ clearConversationUnread: (conversationId: number) => void; /** * 清除所有会话的未读数 */ clearAllConversationUnread: () => void; /** * 获取联系人列表 * @param contactType 联系人类型 * @param groupId 群组ID(可选) * @param pageNo 页码,默认 1 * @param pageSize 每页大小,默认 50 * @returns 联系人列表Promise */ getContactByType: (contactType: ContactType, groupId?: number, pageNo?: number, pageSize?: number) => Promise>; /** * 获取会员联系人列表 * @param groupId 群组ID(可选) * @returns 会员联系人列表Promise */ getMemberContacts: (groupId?: number) => Promise>; /** * 获取同事联系人列表 * @param groupId 群组ID(可选) * @returns 同事联系人列表Promise */ getColleagueContacts: (groupId?: number) => Promise>; /** * 获取群聊联系人列表 * @param groupId 群组ID(可选) * @returns 群聊联系人列表Promise */ getGroupContacts: (groupId?: number) => Promise>; /** * 编辑联系人分组 * @param editeContactTagDTO 编辑联系人标签DTO * @returns 编辑结果Promise */ editContactTag: (editeContactTagDTO: EditeContactTagDTO) => Promise>; /** * 获取联系人分组 * @param contactType 联系人类型 * @returns 联系人分组Promise */ getContactTag: (contactType: ContactType) => Promise>; /** * 分配联系人标签 * @param allocationContactTagDTO 分配联系人标签DTO * @returns 分配结果Promise */ allocationContactTag: (allocationContactTagDTO: AllocationContactTagDTO) => Promise>; /** * 为会员分配标签 * @param tag 标签名称 * @param groupIds 群组ID列表 * @param type 0: 添加分组, 1: 删除分组 * @returns 分配结果Promise */ allocationMemberTag: (tag: string, groupIds: number[], type?: number) => Promise>; /** * 为同事分配标签 * @param tag 标签名称 * @param groupIds 群组ID列表 * @param type 0: 添加分组, 1: 删除分组 * @returns 分配结果Promise */ allocationColleagueTag: (tag: string, groupIds: number[], type?: number) => Promise>; /** * 为群聊分配标签 * @param tag 标签名称 * @param groupIds 群组ID列表 * @param type 0: 添加分组, 1: 删除分组 * @returns 分配结果Promise */ allocationGroupTag: (tag: string, groupIds: number[], type?: number) => Promise>; get uuid(): string; /** * 推送消息到达时更新会话列表缓存(latest / 未读等) * @param message 消息 */ private updateMessageCache; /** * 安排会话列表更新事件(按 queryType 分桶)。 * * 节流只限制「何时 flush」,不限制「记哪些 queryType」:每次先 add 进 pending Set, * 500ms 窗口内多次 schedule 会合并为一次 flush,flush 时对 Set 内每个 queryType 各发一次 * OnConversationListUpdated(见 emitConversationListUpdatedForQueryTypes)。因此同时推 3、6 等 * 不会丢桶;仅有定时器时 return 表示不再叠第二个定时器,pending 里已包含此前全部 queryType。 */ private scheduleConversationUpdate; /** * 立即触发会话列表更新事件(按 queryType 分别触发) */ private flushConversationUpdate; } export default SIMSDK;