k2-im 0.1.19 → 0.1.21

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.
@@ -43,7 +43,7 @@ interface ConversationDraft$1 {
43
43
  updatedAt: number;
44
44
  }
45
45
  /** 消息内容类型。sticker=表情/贴图(BMessage contentType=7);call=单聊通话记录(contentType=10);transfer=转账(contentType=16);miniProgram=小程序分享卡(contentType=22);redPacket=红包卡(contentType=25);game=小游戏(contentType=27);未知 wire 正文统一归一为 unknown。 */
46
- type MessageContentType = 'text' | 'system' | 'image' | 'video' | 'voice' | 'file' | 'sticker' | 'contact' | 'miniProgram' | 'game' | 'transfer' | 'call' | 'redPacket' | 'unknown';
46
+ type MessageContentType = 'text' | 'system' | 'image' | 'video' | 'voice' | 'file' | 'sticker' | 'contact' | 'miniProgram' | 'game' | 'transfer' | 'call' | 'redPacket' | 'mediaAlbum' | 'unknown';
47
47
  /**
48
48
  * 发送态(客户端态):消息从本地创建到服务端确认的生命周期。
49
49
  * `uploading` 仅媒体消息使用:文件上传阶段(uploading→pending→sending→sent);
@@ -53,7 +53,7 @@ type MessageSendStatus = 'pending' | 'uploading' | 'sending' | 'sent' | 'failed'
53
53
  /** 送达/已读态(服务端态):消息在对端的回执状态。 */
54
54
  type MessageReceipt = 'unread' | 'delivered' | 'read';
55
55
  /** 群系统提示事件类型(结构化语义;UI/i18n 层据此渲染文案,**不在 mapper 写死中文**)。 */
56
- type ImSystemEventType = 'direct_contact_established' | 'direct_contact_required' | 'direct_message_refused' | 'group_info_changed' | 'group_activated' | 'group_member_joined' | 'group_member_invited' | 'group_member_left' | 'group_member_removed' | 'group_master_changed' | 'group_dismissed' | 'group_member_renamed' | 'group_message_pinned' | 'group_message_unpinned' | 'channel_name_changed' | 'channel_avatar_changed' | 'channel_announcement_changed' | 'channel_member_joined' | 'channel_member_invited' | 'channel_member_left' | 'channel_member_removed' | 'channel_owner_transferred' | 'channel_admin_added' | 'channel_admin_removed' | 'channel_dismissed' | 'channel_all_muted' | 'channel_all_unmuted' | 'channel_created' | 'channel_private_chat_disabled' | 'channel_private_chat_enabled' | 'channel_member_renamed' | 'channel_member_muted' | 'channel_member_unmuted' | 'channel_message_pinned' | 'channel_message_unpinned' | 'channel_unknown' | 'red_packet_claimed' | 'red_packet_claimed_thunder' | 'unknown';
56
+ type ImSystemEventType = 'direct_contact_established' | 'direct_contact_required' | 'direct_message_refused' | 'group_info_changed' | 'group_activated' | 'group_member_joined' | 'group_member_invited' | 'group_member_left' | 'group_member_removed' | 'group_master_changed' | 'group_dismissed' | 'group_member_renamed' | 'group_message_pinned' | 'group_message_unpinned' | 'group_call_started' | 'group_call_ended' | 'group_call_missed' | 'channel_name_changed' | 'channel_avatar_changed' | 'channel_announcement_changed' | 'channel_member_joined' | 'channel_member_invited' | 'channel_member_left' | 'channel_member_removed' | 'channel_owner_transferred' | 'channel_admin_added' | 'channel_admin_removed' | 'channel_dismissed' | 'channel_all_muted' | 'channel_all_unmuted' | 'channel_created' | 'channel_private_chat_disabled' | 'channel_private_chat_enabled' | 'channel_member_renamed' | 'channel_member_muted' | 'channel_member_unmuted' | 'channel_message_pinned' | 'channel_message_unpinned' | 'channel_unknown' | 'red_packet_claimed' | 'red_packet_claimed_thunder' | 'unknown';
57
57
  /** 系统提示结构化内容(contentType==='system'):存语义,不把最终中文句子当主数据源(UI/composable 据 eventType + 资料生成文案)。 */
58
58
  interface ImSystemMessageBody {
59
59
  eventType: ImSystemEventType;
@@ -120,6 +120,23 @@ type LastMessageSummary = {
120
120
  } | {
121
121
  kind: 'voice';
122
122
  durationMs?: number;
123
+ }
124
+ /**
125
+ * 媒体合集(contentType 28)。
126
+ *
127
+ * 只给结构化计数与配文,**不在这里拼「2 张照片, 1 个视频」这种文案**——中英文的量词、复数与
128
+ * 连接符各不相同,必须由 im-i18n 按 locale 组装。`caption` 非空时宿主优先显示配文(对齐三端)。
129
+ *
130
+ * `firstItemKind` 是第一项是照片还是视频。有配文时列表显示的是配文,光看计数无法决定该配
131
+ * 照片图标还是视频图标,三端统一按第一项取(对齐 iOS `IMMediaAlbumMessageBody`)。
132
+ * 入站解析后所有项都被丢弃时缺省,宿主据此不显示类型图标。
133
+ */
134
+ | {
135
+ kind: 'mediaAlbum';
136
+ imageCount: number;
137
+ videoCount: number;
138
+ caption?: string;
139
+ firstItemKind?: 'image' | 'video';
123
140
  } | {
124
141
  kind: 'encrypted';
125
142
  } | {
@@ -422,6 +439,59 @@ interface UnknownMessageBody {
422
439
  reason: 'unsupported-content-type' | 'malformed-content';
423
440
  }
424
441
  /** 按 contentType 的结构化内容体。 */
442
+ /**
443
+ * 媒体合集单项:一张图片或一个视频。
444
+ *
445
+ * 对应协议 `content` JSON 里 `items[]` 的一个元素(wire `mediaType` 1=图片 2=视频)。
446
+ * 与 `ImImageBody` / `ImVideoBody` 的区别是它**不是**独立的一条消息——同一条合集消息里的
447
+ * 若干项共享消息级的撤回、已读、引用与转发语义。
448
+ */
449
+ interface ImMediaAlbumItem {
450
+ /** 该项是图片还是视频;由协议 `mediaType` 归一而来,未知取值的项在解析阶段已被丢弃。 */
451
+ kind: 'image' | 'video';
452
+ /** 远端地址。加密项也是这个地址,解密用本项自己的 `teaKey`。 */
453
+ url: string;
454
+ /** 原始像素宽。宫格按它判定朝向,为 0 时宿主用兜底几何。 */
455
+ width: number;
456
+ /** 原始像素高。 */
457
+ height: number;
458
+ /**
459
+ * 视频时长,**毫秒**。
460
+ *
461
+ * 协议 `items[].duration` 本身就是毫秒,这里不做换算——注意这与单视频消息
462
+ * `ImVideoBody.duration`(秒)单位不同,所以刻意用 `durationMs` 命名区分。图片项没有此字段。
463
+ */
464
+ durationMs?: number;
465
+ /** 远端缩略图地址;可能缺省,此时只能用 `thumbData`。 */
466
+ thumbUrl?: string;
467
+ /** 内嵌缩略图/封面 JPEG 字节。加密消息服务端出不了封面,宫格首屏只能靠它。 */
468
+ thumbData?: Uint8Array;
469
+ /** 原文件 MD5。 */
470
+ md5?: string;
471
+ /** 原文件大小(字节)。 */
472
+ size?: number;
473
+ /** 本项的文件解密 TEA key;`fileEncryptType` 为 0/2/3 时必有。 */
474
+ teaKey?: Uint8Array;
475
+ /** 文件加密类型:0=跟随消息 1=不加密 2=前 32 字节 TEA 3=完整 TEA。 */
476
+ fileEncryptType?: number;
477
+ /** 发送方勾选了「原图」。仅作展示角标,不影响下载与解密。 */
478
+ hd?: boolean;
479
+ }
480
+ /**
481
+ * 媒体合集正文(`contentType === 'mediaAlbum'`,协议 28)。
482
+ *
483
+ * 一条消息同时承载一段可选配文和 1–9 个图片/视频项。产品上的「图文消息」就是
484
+ * `items.length === 1 && caption` 非空的情形,所以**分档判断一律看 `items.length`,不要看 contentType**。
485
+ *
486
+ * `items` 为空数组只会出现在入站解析残缺时(所有项的 `mediaType` 都不认识,或都无法解密);
487
+ * 这种正文不可出站——出站编码会显式拒绝,避免把坏消息转发出去。
488
+ */
489
+ interface ImMediaAlbumBody {
490
+ /** 配文;缺省与空串等价,出站不写空串。 */
491
+ caption?: string;
492
+ /** 媒体项,顺序即用户选择顺序(决定宫格 index 与首项朝向)。 */
493
+ items: readonly ImMediaAlbumItem[];
494
+ }
425
495
  interface ImMessageBody {
426
496
  /** P0 文本内容(明文,解密后的结果)。 */
427
497
  text?: string;
@@ -449,6 +519,8 @@ interface ImMessageBody {
449
519
  call?: ImCallRecordBody;
450
520
  /** contentType==='redPacket' 时的红包卡片。 */
451
521
  redPacket?: ImRedPacketBody;
522
+ /** contentType==='mediaAlbum' 时的媒体合集正文(配文 + 1~9 个图片/视频项)。 */
523
+ mediaAlbum?: ImMediaAlbumBody;
452
524
  /** contentType==='unknown' 时的稳定未知正文,不含原始 wire type。 */
453
525
  unknown?: UnknownMessageBody;
454
526
  }
@@ -483,7 +555,7 @@ type ImMessageFailureReason = 'timeout' | 'rejected' | 'encrypt_failed' | 'netwo
483
555
  * 失败**展示语义**码(强类型枚举,非裸串):供 im-i18n 按 locale 渲染失败气泡文案。
484
556
  * 由 `reason` / `SendMediaFailReason` / ACK errcode 穷尽映射而来,与 im-i18n failure catalog 键一一对应(media.* 带 mediaKind 参数)。
485
557
  */
486
- type ImFailureDisplayCode = 'media.empty' | 'media.noCrypto' | 'media.previewFailed' | 'media.encryptFailed' | 'media.uploadFailed' | 'media.cancelled' | 'media.invalidDuration' | 'media.uploadInterrupted' | 'contactRequired' | 'messageRefused' | 'forbiddenOrLeft' | 'contentRejected' | 'groupDismissed' | 'groupUnavailable' | 'channelDismissed' | 'channelMuted' | 'channelNotMember' | 'channelAdminRequired' | 'conversationUnsupported' | 'sendCanceled' | 'sessionLoggedOut' | 'timeout' | 'network' | 'unknown';
558
+ type ImFailureDisplayCode = 'media.empty' | 'media.noCrypto' | 'media.previewFailed' | 'media.encryptFailed' | 'media.uploadFailed' | 'media.cancelled' | 'media.invalidDuration' | 'media.uploadInterrupted' | 'media.contentTooLarge' | 'contactRequired' | 'messageRefused' | 'forbiddenOrLeft' | 'contentRejected' | 'groupDismissed' | 'groupUnavailable' | 'channelDismissed' | 'channelMuted' | 'channelNotMember' | 'channelAdminRequired' | 'conversationUnsupported' | 'sendCanceled' | 'sessionLoggedOut' | 'timeout' | 'network' | 'unknown';
487
559
  interface ImMessageFailure {
488
560
  /** 归一后的错误码(来自 MESChatAck.errcode 或本地失败码,本地码用负值)。 */
489
561
  code: number;
@@ -511,7 +583,12 @@ interface MediaTaskUpdate {
511
583
  direction: 'upload' | 'download';
512
584
  state: 'queued' | 'running' | 'completed' | 'failed' | 'canceled';
513
585
  percent: number;
514
- /** upload 任务子阶段;finalizing 是等待远端 URL 最终确认。 */
586
+ /**
587
+ * upload 任务子阶段。
588
+ *
589
+ * `waiting-upload-slot` 与 `state: 'queued'` 同时出现,表示还没开始传字节(在生成缩略图或在等上传槽位),
590
+ * 此时 percent 恒为 0;`transferring` 正在传字节;`finalizing` 是等待远端 URL 最终确认。
591
+ */
515
592
  phase?: 'waiting-upload-slot' | 'transferring' | 'finalizing';
516
593
  failure?: ImMessageFailure;
517
594
  }
@@ -1612,9 +1689,23 @@ interface MediaAssetCacheKey {
1612
1689
  messageId: string;
1613
1690
  resourceVersion: string;
1614
1691
  }
1615
- /** 已解密的真实媒体资产;字节可结构化克隆并可在未来作为 Worker transferable。 */
1692
+ /**
1693
+ * 已解密的真实媒体资产。
1694
+ *
1695
+ * 内容用 `Blob` 承载而不是 `Uint8Array`:图片、尤其视频可达上百 MB,读成 `Uint8Array` 就等于把整份
1696
+ * 媒体搬进 JS 堆;`Blob` 的字节由浏览器自己托管,写缓存、读缓存和交给 `<img>` / `<video>` 全程都不需要
1697
+ * 整读一遍。字段名从 `bytes` 改成 `blob` 是刻意的——改名让编译器强制每个读写点重新被检查,也不会留下
1698
+ * 「有时是字节、有时是 Blob」两条内存表现完全不同的路径。
1699
+ *
1700
+ * `Blob` 可结构化克隆,因此 IndexedDB 能直接存,未来跨 Worker 传递也不需要改形状。
1701
+ */
1616
1702
  interface MediaAssetCacheEntry extends MediaAssetCacheKey {
1617
- bytes: Uint8Array;
1703
+ /** 解密后的真实媒体内容;字节量一律按 `blob.size` 核算(LRU、单条上限、诊断都用它)。 */
1704
+ blob: Blob;
1705
+ /**
1706
+ * 消息体声明的 MIME。保留该字段而不是依赖 `blob.type`:解密产物的 Blob 可能没有类型,也可能带的是
1707
+ * 下载响应的类型,与消息声明不一定一致;读缓存时要以消息声明为准。
1708
+ */
1618
1709
  mimeType?: string;
1619
1710
  }
1620
1711
  /** 单种媒体的 sibling 缓存策略。 */
@@ -1632,7 +1723,7 @@ interface MediaAssetCacheStrategyRegistry {
1632
1723
  /**
1633
1724
  * 明文媒体资产缓存 Port。
1634
1725
  *
1635
- * Core/SDK 只通过该端口读写真实媒体字节;IndexedDB、配额与 LRU 由浏览器实现负责。
1726
+ * Core/SDK 只通过该端口读写真实媒体内容(以 Blob 承载);IndexedDB、配额与 LRU 由浏览器实现负责。
1636
1727
  */
1637
1728
  interface MediaAssetCachePort {
1638
1729
  get: (key: MediaAssetCacheKey) => Promise<MediaAssetCacheEntry | null>;
@@ -1652,8 +1743,14 @@ interface ImProfilePort {
1652
1743
  clearCache?: () => void;
1653
1744
  }
1654
1745
 
1655
- /** 会话收藏可展示的内容类型;与 iOS `isSupportCollectionMsgType` 对齐。 */
1656
- type ImSessionFavoriteKind = 'text' | 'image' | 'video' | 'voice' | 'location' | 'file';
1746
+ /**
1747
+ * 会话收藏可展示的内容类型;与 iOS `isSupportCollectionMsgType` 对齐。
1748
+ *
1749
+ * @remarks 这些值与收藏接口的 `content_type` 数值一一对应,而那个数值就是消息自己的 contentType
1750
+ * (1=文本 2=图片 3=视频 4=语音 5=位置 11=文件 **28=媒体合集**),不是另一套收藏专用枚举。
1751
+ * Android `MessageCollectExecute` 直接写 `message.getContentType()`,iOS 写 `msg.msgType`,两端一致。
1752
+ */
1753
+ type ImSessionFavoriteKind = 'text' | 'image' | 'video' | 'voice' | 'location' | 'file' | 'mediaAlbum';
1657
1754
  /** 服务端一条会话收藏快照;列表以 HTTP 为准,不回写原消息。 */
1658
1755
  interface ImSessionFavoriteItem$1 {
1659
1756
  readonly collectId: string;
@@ -2390,6 +2487,10 @@ type ForwardCandidateMessage = ForwardContentCandidate & Pick<ImMessage, 'encryp
2390
2487
  /**
2391
2488
  * 多选转发时是否需要先提示用户“剔除后继续”。
2392
2489
  * 覆盖语音、所有显式 unknown 与解密失败;原始 wire 类型不进入产品判定。
2490
+ *
2491
+ * 点名的都是**根本转不出去**的类型(语音、通话记录、unknown 都没有注册转发策略),提示的含义是
2492
+ * “这几条会被剔除”。已注册策略的类型一律不在此列——**媒体合集也不在**:它和图片/视频一样整条正文
2493
+ * 克隆、不重新上传,把它加进来会对一条能完整转发的消息发出假警告。
2393
2494
  */
2394
2495
  declare function requiresForwardTypeConfirmation(message: ForwardCandidateMessage): boolean;
2395
2496
  /**
@@ -2410,6 +2511,38 @@ declare function canTransmit(message: ForwardCandidateMessage): boolean;
2410
2511
 
2411
2512
  type RecallFailReason = 'not-found' | 'not-own' | 'not-sent' | 'expired' | 'unsupported' | 'timeout' | 'server-expired' | 'failed' | 'disconnected';
2412
2513
 
2514
+ /** 浏览器 PushSubscription.toJSON() 的可移植数据;不依赖 DOM 或浏览器全局。 */
2515
+ interface ImWebPushSubscription {
2516
+ endpoint?: string;
2517
+ expirationTime?: number | null;
2518
+ keys?: Record<string, string>;
2519
+ }
2520
+ /** 状态不包含 endpoint、加密密钥或登录凭据,可安全用于设置页。 */
2521
+ interface ImPushSnapshot {
2522
+ status: 'idle' | 'pending' | 'syncing' | 'synced' | 'unconfirmed' | 'error' | 'disposed';
2523
+ error?: 'timeout' | 'invalid-ack' | 'server-rejected' | 'send-failed';
2524
+ /** unconfirmed 表示已收到旧后端默认错误码 ACK,不能据此证明绑定成功或失败。 */
2525
+ serverCode?: number;
2526
+ /** 超时等失败后等下一条连接恢复;不主动反复重报或制造重连。 */
2527
+ requiresReconnect?: boolean;
2528
+ }
2529
+ /**
2530
+ * 当前账号的推送绑定。浏览器授权、订阅和取消订阅由宿主拥有。
2531
+ * setWebSubscription 只提交同步意图;只有 snapshot.status === 'synced' 表示收到服务端成功 ACK。
2532
+ */
2533
+ interface ImPushApi {
2534
+ /** 必须携带创建订阅时的账号,防止异步结果被交给另一个账号。离线时保留最新意图。 */
2535
+ setWebSubscription: (input: {
2536
+ userId: string;
2537
+ subscription: ImWebPushSubscription;
2538
+ }) => void;
2539
+ /** 停止本地同步并释放订阅数据;不宣称服务端解绑,宿主仍须调用 PushSubscription.unsubscribe()。 */
2540
+ clear: () => void;
2541
+ snapshot: () => ImPushSnapshot;
2542
+ /** 立即提供快照,返回退订函数;监听器的异常经宿主错误端口报告。 */
2543
+ subscribe: (listener: (snapshot: ImPushSnapshot) => void) => () => void;
2544
+ }
2545
+
2413
2546
  /**
2414
2547
  * IM 语义文案 catalog 的键、参数和完整性合同。
2415
2548
  * 键描述领域含义而非组件位置,使 Web/H5/SSR 可共享 formatter,宿主布局文案不进入此 schema。
@@ -2420,7 +2553,7 @@ type RecallFailReason = 'not-found' | 'not-own' | 'not-sent' | 'expired' | 'unsu
2420
2553
  * 二期收敛:kit 框架无关层不再直接产中文,改产本联合里的码 + 参数(如 {reason}/{label}/{size}),由宿主经 im-i18n 渲染。
2421
2554
  * 动态原始报错(error.message)作为 `{reason}` 参数拼接,不入 catalog(属诊断,不翻译)。
2422
2555
  */
2423
- type ImServiceTextKey = 'common.notConnected' | 'common.selectOrOpenConversation' | 'common.conversationTypeNotReady' | 'common.conversationNotReady' | `recall.${RecallFailReason}` | `edit.${EditFailReason}` | 'localDelete.done' | 'localDelete.notFound' | 'localDelete.inFlight' | 'localDelete.failed' | 'channelDelete.notFound' | 'channelDelete.unsupported' | 'channelDelete.notSent' | 'channelDelete.unavailable' | 'channelDelete.forbidden' | 'channelDelete.timeout' | 'channelDelete.failed' | 'channelDelete.disconnected' | 'directBlock.contactRequired' | 'groupBlock.left' | 'groupBlock.removed' | 'groupBlock.dismissed' | 'groupBlock.unknownRestricted' | 'channelBlock.guest' | 'channelBlock.left' | 'channelBlock.removed' | 'channelBlock.dismissed' | 'channelBlock.muted' | 'channelBlock.allMembersMuted' | 'channelBlock.currentUserMuted' | 'channelBlock.blacklisted' | 'channelBlock.unknownRestricted' | 'channelProfile.loadFailed' | 'channelProfile.notFound' | 'channelProfile.retryAction' | 'channelMembers.title' | 'channelMembers.searchPlaceholder' | 'channelMembers.loading' | 'channelMembers.loadFailed' | 'channelMembers.retryAction' | 'channelMembers.empty' | 'channelMembers.loadingMore' | 'channelMembers.loadMoreFailed' | 'channelMembers.exhausted' | 'channelMembers.loadMoreAction' | 'label.image' | 'label.video' | 'label.file' | 'label.sticker' | 'send.failed' | 'send.retryFailed' | 'send.cancelFailed' | 'send.mediaFailed' | 'send.mediaEmpty' | 'send.mediaCancelled' | 'send.mediaCountLimit' | 'send.mediaTooLarge' | 'send.videoTooLong' | 'send.videoDurationUnavailable' | 'send.voiceEmpty' | 'send.voiceStorageNotConfigured' | 'send.voiceCancelled' | 'send.voiceFailed' | 'media.voiceNotReady' | 'media.voiceLoadEmpty' | 'media.voiceLoadFailed' | 'media.videoOpenEmpty' | 'media.videoLoadFailed' | 'media.imageInvalid' | 'media.imageLoadFailed' | 'media.fileDownloadEmpty' | 'media.fileDownloadFailed' | 'conversation.muteEnableFailed' | 'conversation.muteDisableFailed' | 'read.markReadFailed' | 'pinned.forbidden' | 'pinned.network' | 'pinned.contract' | 'pinned.unsupported' | 'pinned.failed' | 'pinned.previewUnavailable' | 'pinned.locateFailed' | 'pinned.recalled' | 'pinned.deleted' | 'pinned.protected' | 'pinned.pinAction' | 'pinned.unpinAction' | 'pinned.unpinConfirm' | 'pinned.cancelAction' | 'lifecycle.missingLoginState' | 'lifecycle.prepareFailed' | 'lifecycle.missingConnectParams' | 'lifecycle.connectFailed' | 'lifecycle.disposed' | 'forward.emptyInput' | 'forward.allSkipped' | 'forward.partialSkipped' | 'forward.done' | 'forward.failed';
2556
+ type ImServiceTextKey = 'common.notConnected' | 'common.selectOrOpenConversation' | 'common.conversationTypeNotReady' | 'common.conversationNotReady' | `recall.${RecallFailReason}` | `edit.${EditFailReason}` | 'localDelete.done' | 'localDelete.notFound' | 'localDelete.inFlight' | 'localDelete.failed' | 'channelDelete.notFound' | 'channelDelete.unsupported' | 'channelDelete.notSent' | 'channelDelete.unavailable' | 'channelDelete.forbidden' | 'channelDelete.timeout' | 'channelDelete.failed' | 'channelDelete.disconnected' | 'directBlock.contactRequired' | 'groupBlock.left' | 'groupBlock.removed' | 'groupBlock.dismissed' | 'groupBlock.unknownRestricted' | 'channelBlock.guest' | 'channelBlock.left' | 'channelBlock.removed' | 'channelBlock.dismissed' | 'channelBlock.muted' | 'channelBlock.allMembersMuted' | 'channelBlock.currentUserMuted' | 'channelBlock.blacklisted' | 'channelBlock.unknownRestricted' | 'channelProfile.loadFailed' | 'channelProfile.notFound' | 'channelProfile.retryAction' | 'channelMembers.title' | 'channelMembers.searchPlaceholder' | 'channelMembers.loading' | 'channelMembers.loadFailed' | 'channelMembers.retryAction' | 'channelMembers.empty' | 'channelMembers.loadingMore' | 'channelMembers.loadMoreFailed' | 'channelMembers.exhausted' | 'channelMembers.loadMoreAction' | 'label.image' | 'label.video' | 'label.file' | 'label.sticker' | 'send.failed' | 'send.retryFailed' | 'send.cancelFailed' | 'send.mediaFailed' | 'send.mediaEmpty' | 'send.mediaCancelled' | 'send.mediaCountLimit' | 'send.mediaTooLarge' | 'send.mediaFormatMismatch' | 'send.videoTooLong' | 'send.videoDurationUnavailable' | 'send.voiceEmpty' | 'send.voiceStorageNotConfigured' | 'send.voiceCancelled' | 'send.voiceFailed' | 'media.uploadWaiting' | 'media.voiceNotReady' | 'media.voiceLoadEmpty' | 'media.voiceLoadFailed' | 'media.videoOpenEmpty' | 'media.videoLoadFailed' | 'media.imageInvalid' | 'media.imageLoadFailed' | 'media.fileDownloadEmpty' | 'media.fileDownloadFailed' | 'conversation.muteEnableFailed' | 'conversation.muteDisableFailed' | 'conversation.backgroundLoadFailed' | 'read.markReadFailed' | 'storage.failed' | 'sync.failed' | 'draft.saveFailed' | 'history.returnLatestFailed' | 'pinned.forbidden' | 'pinned.network' | 'pinned.contract' | 'pinned.unsupported' | 'pinned.failed' | 'pinned.previewUnavailable' | 'pinned.locateFailed' | 'pinned.recalled' | 'pinned.deleted' | 'pinned.protected' | 'pinned.pinAction' | 'pinned.unpinAction' | 'pinned.unpinConfirm' | 'pinned.cancelAction' | 'lifecycle.missingLoginState' | 'lifecycle.prepareFailed' | 'lifecycle.missingConnectParams' | 'lifecycle.connectFailed' | 'lifecycle.disposed' | 'forward.emptyInput' | 'forward.allSkipped' | 'forward.partialSkipped' | 'forward.done' | 'forward.failed';
2424
2557
 
2425
2558
  /**
2426
2559
  * 后端协议的目标服务命名。
@@ -2660,9 +2793,19 @@ interface MediaTransferAdapterConfig {
2660
2793
  rangeDownload?: boolean;
2661
2794
  /**
2662
2795
  * 媒体发送阶段的并发上限;由 im-core 消费,adapter 本身仍只负责单个上传任务。
2663
- * 缺省为 4,允许 1-6;高并发会提高吞吐,也会增加文件加密的内存峰值。
2796
+ *
2797
+ * 并发按媒体体积分两档:图片与不超过分片阈值(16 MiB)的小文件走单次 PutObject、不占分片缓冲,
2798
+ * 缺省 5;视频与超过阈值(或字节数未知)的文件走分片,每路各带分片缓冲,缺省 3。
2799
+ * 两档都只接受 1-6 的整数,超出范围由 core 显式报错。
2800
+ * - 传一个数字:所有媒体共用这一个并发数,与分档前的语义一致。
2801
+ * - 传 `{ total, largeFiles }`:显式分档,`largeFiles` 不得超过 `total`。
2664
2802
  */
2665
- maxConcurrentUploads?: number;
2803
+ maxConcurrentUploads?: number | {
2804
+ /** 在途上传总数上限(两档合计);缺省 5。 */
2805
+ total?: number;
2806
+ /** 其中大文件档的上限(视频、超过分片阈值或字节数未知的内容);缺省 min(3, total)。 */
2807
+ largeFiles?: number;
2808
+ };
2666
2809
  }
2667
2810
 
2668
2811
  interface NetworkEventTarget {
@@ -2808,12 +2951,16 @@ interface ImMessageReactions {
2808
2951
  aggregates: readonly ImMessageReactionAggregate[];
2809
2952
  }
2810
2953
  /** 可渲染媒体正文;密钥和底层文件加密策略只允许留在 SDK/Core。 */
2811
- interface ImMessageViewBody extends Omit<ImMessageBody, 'image' | 'video' | 'voice' | 'file' | 'sticker'> {
2954
+ interface ImMessageViewBody extends Omit<ImMessageBody, 'image' | 'video' | 'voice' | 'file' | 'sticker' | 'mediaAlbum'> {
2812
2955
  image?: Readonly<Omit<NonNullable<ImMessageBody['image']>, 'teaKey' | 'fileEncryptType'>>;
2813
2956
  video?: Readonly<Omit<NonNullable<ImMessageBody['video']>, 'teaKey' | 'fileEncryptType'>>;
2814
2957
  voice?: Readonly<Omit<NonNullable<ImMessageBody['voice']>, 'teaKey' | 'fileEncryptType'>>;
2815
2958
  file?: Readonly<Omit<NonNullable<ImMessageBody['file']>, 'teaKey' | 'fileEncryptType'>>;
2816
2959
  sticker?: Readonly<NonNullable<ImMessageBody['sticker']>>;
2960
+ /** 合集的每一项都带自己的密钥材料,逐项剥离后才交给产品层;按项下载走 SDK handle,不需要这些字段。 */
2961
+ mediaAlbum?: Readonly<Omit<NonNullable<ImMessageBody['mediaAlbum']>, 'items'> & {
2962
+ items: readonly Readonly<Omit<ImMediaAlbumItem, 'teaKey' | 'fileEncryptType'>>[];
2963
+ }>;
2817
2964
  }
2818
2965
  /**
2819
2966
  * 官方 Chat Kit 与宿主消息线程使用的完整稳定消息 DTO。
@@ -2889,6 +3036,44 @@ interface MiniProgramMessageOptions {
2889
3036
  interface TransferMessageOptions {
2890
3037
  replyToMessageId?: string;
2891
3038
  }
3039
+ /**
3040
+ * 媒体合集里的一项:一张图片或一个视频。
3041
+ *
3042
+ * @remarks `kind` 由**调用方**按 MIME 分类,SDK 不嗅探文件内容——宿主的文件选择器本来就要按类型分流
3043
+ * (GIF 得走 `sendGif`),再让 SDK 猜一次只会多一处口径不一致。
3044
+ */
3045
+ interface MediaAlbumItemInput {
3046
+ /** 这一项是图片还是视频。 */
3047
+ kind: 'image' | 'video';
3048
+ /** 原文件;`File` 可直接传,`Blob` 需调用方保证 `type` 可判定。 */
3049
+ file: File | Blob;
3050
+ /** 宿主创建的本地 object URL,仅供上传中的宫格显示这一格;URL 释放由宿主生命周期负责。 */
3051
+ localPreviewUrl?: string;
3052
+ /**
3053
+ * 这一项的本地宽高(视频再带时长与首帧)。
3054
+ *
3055
+ * 不传时 SDK 会自己读一次(与单图/单视频同一条预览路径)。宫格的格子几何按原始宽高算,
3056
+ * 缺了它整条消息的格子比例会在上传完成时跳变。
3057
+ */
3058
+ localPreviewMetadata?: ImagePreviewMetadata | VideoPreviewMetadata;
3059
+ }
3060
+ /**
3061
+ * 媒体合集发送选项。
3062
+ *
3063
+ * @remarks 恰好 1 项且没有配文时,SDK 内部会回落成普通图片/视频消息(与 Android / iOS / 旧 H5 一致),
3064
+ * 此时返回的仍是同样的 `SendMessageResult`,调用方不需要区分。
3065
+ */
3066
+ interface MediaAlbumMessageOptions {
3067
+ /** 配文,最长 1024 字符;纯空白等同于没有配文。超长由 SDK 明确拒绝,**不静默截断**。 */
3068
+ caption?: string;
3069
+ replyToMessageId?: string;
3070
+ /**
3071
+ * 发送方勾选了「原图」,写进每一项的 `hd` 标记。
3072
+ *
3073
+ * 本期不做任何图片/视频压缩,勾与不勾都发原文件,这个字段只让接收端显示「原图」角标。
3074
+ */
3075
+ hd?: boolean;
3076
+ }
2892
3077
  /**
2893
3078
  * 本地视频的固有尺寸、时长与首帧封面。
2894
3079
  *
@@ -3951,6 +4136,22 @@ type ConversationLastMessageSummary = {
3951
4136
  } | {
3952
4137
  kind: 'voice';
3953
4138
  durationMs?: number;
4139
+ }
4140
+ /**
4141
+ * 媒体合集(一条消息内 1~9 个图片/视频 + 可选配文)。
4142
+ *
4143
+ * 只给计数与配文,数量文案由宿主经 im-i18n 按 locale 组装;有配文时优先显示配文。
4144
+ * 两个计数都为 0 表示入站正文残缺(所有项都无法解析),宿主应按未知正文处理。
4145
+ *
4146
+ * `firstItemKind` 是第一项是照片还是视频。有配文时列表显示的是配文,光看计数决定不了该配
4147
+ * 照片图标还是视频图标,三端统一按第一项取;正文残缺时缺省,宿主据此不显示类型图标。
4148
+ */
4149
+ | {
4150
+ kind: 'mediaAlbum';
4151
+ imageCount: number;
4152
+ videoCount: number;
4153
+ caption?: string;
4154
+ firstItemKind?: 'image' | 'video';
3954
4155
  } | {
3955
4156
  kind: 'encrypted';
3956
4157
  } | {
@@ -4403,6 +4604,16 @@ interface ConversationMessageApi {
4403
4604
  sendFile: (file: File | Blob, options?: FileMessageOptions) => Promise<SendMessageResult>;
4404
4605
  /** 发送 GIF 贴图;原文件明文上传 sticker bucket,消息固定 EXPRESSION/LINK/GIF。 */
4405
4606
  sendGif: (file: File | Blob, options?: GifMessageOptions) => Promise<SendMessageResult>;
4607
+ /**
4608
+ * 发送媒体合集:1~9 个图片/视频合成**一条**消息,可带一段配文。
4609
+ *
4610
+ * @remarks 全部项上传成功才发出;任一项失败整条失败,不发半条消息。恰好 1 项且没有配文时
4611
+ * SDK 内部回落成普通图片/视频消息(三端一致)。**校验是整条的**——某一项超限会拒绝整条,
4612
+ * 因为协议上它就是一条消息,没有「发一半」这种状态。
4613
+ *
4614
+ * GIF 不能进合集(三端一致),调用方要先按 MIME 把它拆出去走 `sendGif`。
4615
+ */
4616
+ sendMediaAlbum: (items: readonly MediaAlbumItemInput[], options?: MediaAlbumMessageOptions) => Promise<SendMessageResult>;
4406
4617
  /** 发送已经托管在远端的静态贴图;资源和贴图包身份均为必填合同。 */
4407
4618
  sendSticker: (asset: ImStickerAssetInput, options?: ExpressionMessageOptions) => Promise<SendMessageResult>;
4408
4619
  /** 发送已经托管在远端的 GIF;Giphy 没有 package identity,输入不得提供 packageId。 */
@@ -4483,6 +4694,43 @@ interface ConversationMessageApi {
4483
4694
  * ```
4484
4695
  */
4485
4696
  forward: (messageIds: readonly string[], targets: readonly ConversationRef<ProductHandleConversationType>[]) => Promise<ForwardMessagesResult>;
4697
+ /**
4698
+ * 把媒体合集里的第 `itemIndex` 项,当成**一条独立的图片或视频消息**转发到多个目标会话。
4699
+ *
4700
+ * 用途:全屏预览里点转发时,用户要转的是当前正在看的这一格,而不是整条合集。
4701
+ *
4702
+ * @remarks
4703
+ * 与 `forward` 的区别是产出的消息类型变了(合集 → 图片/视频),所以是独立方法而不是给 `forward`
4704
+ * 放宽入参。与 `forward` 相同的是:复用该项已有的远端地址与解密 key,**不重新上传**;目标会话仍由
4705
+ * direct/GROUP/CHANNEL 各自的 SendStrategy 组帧入 Outbox。
4706
+ *
4707
+ * 视频项在合集里的时长是毫秒,转成单视频消息时 SDK 会换算成协议要求的秒,调用方不需要处理。
4708
+ * 合集项上的「原图」角标与远端缩略图地址不会带到单媒体消息上——单图/单视频正文没有这两个字段。
4709
+ *
4710
+ * 三种情况进 `failed`:源消息不是媒体合集(`IM_SDK_FORWARD_CONTENT_UNSUPPORTED`)、
4711
+ * `itemIndex` 越界或该项已不存在(`IM_SDK_MEDIA_ALBUM_ITEM_INVALID`)、该项还没有可复用的远端地址
4712
+ * (还在上传或入站残缺,`IM_SDK_FORWARD_MEDIA_NOT_READY`,可重试)。
4713
+ *
4714
+ * **还有一类结果三个数组会全空**:源消息已撤回、已被双删、解密失败、在本地已经查不到,
4715
+ * 或它的类型本身就不可转发时,这条消息在预检阶段就被剔除,只出现在 `skippedSourceMessageIds` 里。
4716
+ * 这与 `forward` 的批量语义一致(批量转发本来就要把不可转的源剔掉再发其余的),
4717
+ * 但单条调用时它意味着**什么都没发出去**。所以调用方判成功要看 `sent`,
4718
+ * 不要只判 `failed.length > 0`——那样在「预览期间原消息被撤回」这种竞态下会既不发送也不提示。
4719
+ *
4720
+ * @param messageId 当前 handle 中的合集消息 id。
4721
+ * @param itemIndex 宫格里的项下标,从 0 起;必须是非负整数。
4722
+ * @param targets 目标会话,最多 9 个。
4723
+ * @example
4724
+ * ```ts
4725
+ * const result = await handle.messages.forwardMediaAlbumItem('message-42', 2, [
4726
+ * { conversationType: 'direct', conversationId: '1001' },
4727
+ * ])
4728
+ * // 一条都没发出去就要提示:失败原因在 failed 里,源消息被剔除时 failed 也是空的。
4729
+ * if (result.sent.length === 0)
4730
+ * showError(result.failed[0]?.error.code ?? 'IM_SDK_FORWARD_CONTENT_UNSUPPORTED')
4731
+ * ```
4732
+ */
4733
+ forwardMediaAlbumItem: (messageId: string, itemIndex: number, targets: readonly ConversationRef<ProductHandleConversationType>[]) => Promise<ForwardMessagesResult>;
4486
4734
  /**
4487
4735
  * 按 id 向服务端取回本地没有的消息,并回填进本地历史。
4488
4736
  *
@@ -4692,6 +4940,14 @@ interface ImMessageRef {
4692
4940
  conversation: ConversationRef<ProductHandleConversationType>;
4693
4941
  /** 当前会话内的稳定消息 id。 */
4694
4942
  messageId: string;
4943
+ /**
4944
+ * 媒体合集里的第几项(从 0 起)。
4945
+ *
4946
+ * **只有合集消息需要它,也只有合集消息接受它**:一条合集是一条消息、多个文件,光靠 messageId
4947
+ * 指不到具体某一项。给单媒体消息传这个字段会被显式拒绝,而不是忽略——忽略的话调用方以为自己
4948
+ * 在下载第 3 项,实际拿到的是整条消息的唯一媒体。
4949
+ */
4950
+ itemIndex?: number;
4695
4951
  }
4696
4952
  /**
4697
4953
  * 可观察媒体上传/下载任务的只读产品投影。
@@ -4706,13 +4962,27 @@ interface ImMediaTask {
4706
4962
  messageId: string;
4707
4963
  /** 关联消息的精确会话 sibling。 */
4708
4964
  ref: ConversationRef<ProductHandleConversationType>;
4965
+ /**
4966
+ * 媒体合集的项下标;单媒体消息与全部上传任务为 undefined。
4967
+ *
4968
+ * 一条合集的多项共用同一个 messageId,各自是独立的下载任务。调用方按 messageId 找任务时
4969
+ * 必须连这个字段一起比,否则并发下载两项时会把另一项的进度读成自己的。
4970
+ * 上传任务不带下标:一条合集整体只有一条上传进度(所有项都传完才算这条消息发出去)。
4971
+ */
4972
+ itemIndex?: number;
4709
4973
  /** upload 来自发送链路,download 来自本产品 API。 */
4710
4974
  direction: 'upload' | 'download';
4711
4975
  /** 终态 completed/failed/canceled 不会被同一尝试的迟到 progress 回退。 */
4712
4976
  state: 'queued' | 'running' | 'completed' | 'failed' | 'canceled';
4713
4977
  /** 0-100 的归一化整数。 */
4714
4978
  percent: number;
4715
- /** upload 子阶段;finalizing 为等待对象存储确认。 */
4979
+ /**
4980
+ * upload 子阶段。
4981
+ *
4982
+ * `waiting-upload-slot` 与 `state: 'queued'` 同时出现,表示这条媒体还没开始传字节(在生成缩略图或在
4983
+ * 等上传槽位),此时 `percent` 恒为 0——宿主应显示「等待中」而不是把 0 当成停住的进度。
4984
+ * `transferring` 是正在传字节,`finalizing` 是字节已传完、在等对象存储确认。
4985
+ */
4716
4986
  phase?: 'waiting-upload-slot' | 'transferring' | 'finalizing';
4717
4987
  /** 可供产品按 code/category 决策的稳定错误;不含底层 URL、密钥或响应正文。 */
4718
4988
  error?: ImSdkErrorShape;
@@ -4768,6 +5038,31 @@ interface ImMediaTasksApi {
4768
5038
  * @throws 持久缓存读取失败时抛 `IM_SDK_MEDIA_CACHE_READ_FAILED`,不能把存储故障伪装成 cache miss。
4769
5039
  */
4770
5040
  getCached: (message: ImMessageRef) => Promise<Blob | null>;
5041
+ /**
5042
+ * 为宿主手里的**本地**图片/视频文件预读展示元信息:尺寸、视频时长、视频首帧封面的 JPEG 字节。
5043
+ *
5044
+ * 给「发送前预览」这类场景用:宿主要在用户还没点发送时就把缩略图画出来,而浏览器读不出视频的
5045
+ * 首帧——`<video preload="metadata">` 在 iOS Safari 上只加载元信息、**不解码任何一帧**,
5046
+ * 拿它当缩略图会得到一个空白格子(还会白占一路解码)。
5047
+ *
5048
+ * 返回的对象可以**原样**作为 `localPreviewMetadata` 交给 `sendImage` / `sendVideo` /
5049
+ * `sendMediaAlbum`:发送链路会跳过重复解码,上传中的气泡也从第一帧就有封面。
5050
+ * 视频封面用的就是发送链路那套规格(长边 320、JPEG),所以弹层里看到的与最终发出去的是同一张。
5051
+ *
5052
+ * @param input.kind 按文件类型选解码路径;`'video'` 才会抽首帧与读时长。
5053
+ * @param input.file 本地文件;不会被上传,也不会进任何缓存。
5054
+ * @param input.signal 宿主放弃时中止解码(例如预览弹层被关掉)。
5055
+ * @returns 解码成功返回元信息;**浏览器确实读不出这个文件**(格式不支持、解码超时)时返回 `null`,
5056
+ * 调用方应当显式呈现「这个文件读不出来」,不要拿空白格子糊过去。失败原因会记入 SDK 结构化诊断。
5057
+ * @throws 宿主通过 `signal` 中止时抛 `AbortError`——那是调用方自己的取消,不能和「读不出来」混为一谈。
5058
+ * @throws runtime 已 logout/dispose 时抛 `IM_SDK_MEDIA_RUNTIME_INACTIVE`;
5059
+ * 未装配预览端口时抛 `IM_SDK_MEDIA_PREVIEW_UNAVAILABLE`,不静默返回 `null`。
5060
+ */
5061
+ prepareLocalPreview: <TKind extends 'image' | 'video'>(input: {
5062
+ kind: TKind;
5063
+ file: Blob;
5064
+ signal?: AbortSignal;
5065
+ }) => Promise<(TKind extends 'video' ? VideoPreviewMetadata : ImagePreviewMetadata) | null>;
4771
5066
  }
4772
5067
 
4773
5068
  /**
@@ -5216,14 +5511,8 @@ interface ImSearchApi {
5216
5511
  readonly messages: ImMessageSearchApi;
5217
5512
  }
5218
5513
 
5219
- /**
5220
- * 会话收藏稳定产品门面。
5221
- *
5222
- * 本模块不缓存服务端列表;每次 list/add/delete 都以当前账号 provider 为准。
5223
- * 收藏快照与原聊天消息解耦:原消息删除、撤回或编辑不会回写收藏。
5224
- */
5225
-
5226
5514
  type ImSessionFavoriteItem = Readonly<ImSessionFavoriteItem$1>;
5515
+
5227
5516
  /** 产品层会话收藏 API。 */
5228
5517
  interface ImSessionFavoritesApi {
5229
5518
  list: () => Promise<readonly ImSessionFavoriteItem[]>;
@@ -5742,6 +6031,8 @@ interface AdvancedConversationsApi extends ImConversationsApi, ImConversationBac
5742
6031
  * ```
5743
6032
  */
5744
6033
  interface ImProductClient {
6034
+ /** 当前设备推送订阅的服务端绑定与同步状态。 */
6035
+ readonly push: ImPushApi;
5745
6036
  readonly session: ImSessionApi;
5746
6037
  readonly capabilities: ImConversationCapabilitiesApi;
5747
6038
  readonly conversations: ImConversationListApi;
@@ -5854,6 +6145,13 @@ type ConversationListPreviewSegment = {
5854
6145
  kind: 'legacy-emoji-placeholder';
5855
6146
  text: string;
5856
6147
  };
6148
+ /**
6149
+ * 会话列表摘要文字前面那个类型图标的种类;宿主各自把它映射成自己的 SVG 组件。
6150
+ *
6151
+ * `mediaAlbum` 专指「照片和视频混装」的合集,产品用相机图标;只有照片或只有视频的合集归到
6152
+ * `image` / `video`,因为用户看到的文案也是「2张照片」「2个视频」。
6153
+ */
6154
+ type ConversationListPreviewMediaKind = 'image' | 'video' | 'gif' | 'sticker' | 'mediaAlbum';
5857
6155
  /** 由各宿主按当前产品语言注入的会话列表标签。 */
5858
6156
  interface ConversationListPresentationLabels {
5859
6157
  /** 没有草稿和最后消息时显示的占位文案。 */
@@ -5889,6 +6187,13 @@ interface ConversationListPresentation {
5889
6187
  preview: string;
5890
6188
  /** 不包含 @我提示与发送者前缀的摘要分段。 */
5891
6189
  previewSegments: readonly ConversationListPreviewSegment[];
6190
+ /**
6191
+ * 摘要前面该显示哪个类型图标;不需要图标时缺省。
6192
+ *
6193
+ * 草稿、撤回、管理员删除、系统事件显示的是整句话而不是类型占位,一律不给图标;语音、文件、
6194
+ * 名片等没有产品 glyph 的类型同样不给,它们的文案自带方括号来和真实文本区分。
6195
+ */
6196
+ previewMediaKind?: ConversationListPreviewMediaKind;
5892
6197
  /** 群聊或社群普通消息的发送者前缀;其它摘要为空串。 */
5893
6198
  senderPrefix: string;
5894
6199
  /** 未读 @ 提示;草稿、系统、撤回和管理员删除摘要为空串。 */
@@ -5963,6 +6268,26 @@ declare function resolveBestMediaPresentationSource<TValue>(candidates: readonly
5963
6268
  /** 返回 candidate 是否允许替换当前源;资源质量只能保持或提高,不能异步降级。 */
5964
6269
  declare function canPromoteMediaPresentationSource(current: MediaPresentationSourceQuality, candidate: MediaPresentationSourceQuality): boolean;
5965
6270
 
6271
+ /** 新消息提醒所需的领域与宿主事实;本模块不读取浏览器、路由或全局设置。 */
6272
+ interface MessageNotificationInput {
6273
+ source: 'live' | 'offline';
6274
+ senderId: string;
6275
+ accountId: string;
6276
+ contentType: string;
6277
+ muted: boolean;
6278
+ globallyEnabled: boolean;
6279
+ visibilityState: 'visible' | 'hidden';
6280
+ permission: 'default' | 'denied' | 'granted' | null;
6281
+ }
6282
+ type MessageNotificationDecision = {
6283
+ show: true;
6284
+ } | {
6285
+ show: false;
6286
+ reason: 'not-live' | 'unsupported' | 'permission-denied' | 'page-visible' | 'self-message' | 'system-message' | 'conversation-muted' | 'globally-disabled';
6287
+ };
6288
+ /** PC/H5 共用的实时消息提醒规则;离线历史回放不逐条弹通知。 */
6289
+ declare function resolveMessageNotificationDecision(input: MessageNotificationInput): MessageNotificationDecision;
6290
+
5966
6291
  /**
5967
6292
  * 官方 Chat Kit 和受控诊断工具使用的 SDK internal 入口。
5968
6293
  * 它暴露完整 client、adapter 装配和领域原子,但仍不属于普通产品 API;生产宿主不得据此解析协议或持有密钥。
@@ -6155,6 +6480,13 @@ interface ChatMediaMessageRef {
6155
6480
  conversationId: string;
6156
6481
  /** 需要查找本地媒体预览的消息 ID。 */
6157
6482
  messageId: string;
6483
+ /**
6484
+ * 媒体合集的项下标(第几格)。
6485
+ *
6486
+ * 一条合集的 9 格共用同一个 messageId,各自是独立资源;不带下标会让它们落到同一个注册表键上,
6487
+ * 后绑定的一格把先绑定的挤掉并撤销其地址。单媒体消息不传这个字段。
6488
+ */
6489
+ itemIndex?: number;
6158
6490
  }
6159
6491
  /**
6160
6492
  * Chat Kit 提供给共享 Store 和业务 Service 的账号运行接口。
@@ -6649,6 +6981,31 @@ declare namespace forward_service {
6649
6981
  export type { forward_service_ForwardCommandHooks as ForwardCommandHooks, forward_service_ImForwardOperationResult as ImForwardOperationResult };
6650
6982
  }
6651
6983
 
6984
+ /**
6985
+ * 为宿主手里的本地图片/视频文件预读展示元信息(尺寸、视频时长、视频首帧封面 JPEG 字节)。
6986
+ *
6987
+ * 给「发送前预览」用:宿主要在用户点发送之前就把缩略图画出来。**不要用 `<video>` 当缩略图**——
6988
+ * `preload="metadata"` 在 iOS Safari 上只加载元信息、不解码任何一帧,格子会是空白的,
6989
+ * 而且 N 个文件就是 N 路解码。
6990
+ *
6991
+ * 返回值可以**原样**作为 `localPreviewMetadata` 传给发送命令:发送链路会跳过重复解码,
6992
+ * 上传中的气泡也从第一帧就有封面。视频封面用的就是发送链路那套规格,弹层里看到的与发出去的是同一张。
6993
+ *
6994
+ * @param runtime 当前账号 runtime。
6995
+ * @param input 预读入参。
6996
+ * @param input.kind 文件类型;`'video'` 才会抽首帧与读时长。
6997
+ * @param input.file 本地文件;不上传、不进缓存。
6998
+ * @param input.signal 宿主放弃时中止解码(例如弹层被关掉)。
6999
+ * @returns 解码成功返回元信息;**浏览器确实读不出这个文件**时返回 `null`,
7000
+ * 调用方必须显式呈现「这个文件读不出来」,不要留一块空白让用户以为还在加载。
7001
+ * 账号切换、Client 未就绪同样返回 `null`(此时页面已经不该再画这一格)。
7002
+ * @throws 宿主自己通过 `signal` 中止时抛 `AbortError`;那是调用方的取消,不是文件读不出来。
7003
+ */
7004
+ declare function prepareLocalMediaPreview<TKind extends 'image' | 'video'>(runtime: ChatRuntime, input: {
7005
+ kind: TKind;
7006
+ file: Blob;
7007
+ signal?: AbortSignal;
7008
+ }): Promise<(TKind extends 'video' ? VideoPreviewMetadata : ImagePreviewMetadata) | null>;
6652
7009
  /** 根据文件头确认解密结果是否为 JPEG、PNG、GIF 或 WebP;不是已知图片时返回 `null`,避免页面显示裂图。 */
6653
7010
  declare function detectImageMime(bytes: Uint8Array): string | null;
6654
7011
  /** 根据文件头识别 WebM 或 MP4;无法识别时返回 `video/mp4`,由浏览器播放器继续判断是否能播放。 */
@@ -6658,8 +7015,11 @@ declare function detectVideoMime(bytes: Uint8Array): string;
6658
7015
  *
6659
7016
  * 命中时返回带 `url` 和 `release()` 的使用凭证;组件卸载或换源时必须释放。未命中时返回
6660
7017
  * `undefined`,调用方继续走远端下载。
7018
+ *
7019
+ * 合集必须传 `itemIndex`:发送链路是**按格**把本地地址登记进注册表的,不带下标查的是一个
7020
+ * 不存在的键,结果是刚发出去的合集点开预览还要重新下载一遍远端。
6661
7021
  */
6662
- declare function acquireMediaBlob(runtime: ChatRuntime, message: ImMessageView): MediaObjectUrlLease | undefined;
7022
+ declare function acquireMediaBlob(runtime: ChatRuntime, message: ImMessageView, itemIndex?: number): MediaObjectUrlLease | undefined;
6663
7023
  /**
6664
7024
  * 取得语音播放器需要的完整明文字节。
6665
7025
  *
@@ -6676,6 +7036,26 @@ declare function loadVoiceBytes(runtime: ChatRuntime, message: ImMessageView, ho
6676
7036
  declare function loadVideoObjectUrl(runtime: ChatRuntime, message: ImMessageView, hooks: ServiceNoteHooks, onProgress?: (percent: number) => void): Promise<string | null>;
6677
7037
  /** 仅读取已缓存视频,命中时返回可播放 object URL;miss 不创建下载任务、不显示进度。 */
6678
7038
  declare function loadCachedVideoObjectUrl(runtime: ChatRuntime, message: ImMessageView): Promise<string | null>;
7039
+ /**
7040
+ * 下载并解密媒体合集里的某一项,返回预览器可用的临时地址。
7041
+ *
7042
+ * 图片项与视频项走同一条路径:SDK 端按下标取到这一项的 url/teaKey 后,复用的就是单图/单视频的
7043
+ * 解密 loader,所以这里不需要按 kind 分流。图片项额外做一次真实格式校验(与 `loadImageObjectUrl`
7044
+ * 同一条门槛),不把无效二进制交给 `<img>`。
7045
+ *
7046
+ * 返回 `null` 表示下标越界、正文不是合集、内容非法或下载失败,失败原因经 `setNote` 反馈。
7047
+ * **唯一不反馈的失败是用户自己取消**(关预览浮层时取消这一项的在途下载):同样返回 `null`,但不提示。
7048
+ * **调用方在不再使用地址时必须 `URL.revokeObjectURL`。**
7049
+ */
7050
+ declare function loadMediaAlbumItemObjectUrl(runtime: ChatRuntime, message: ImMessageView, itemIndex: number, hooks: ServiceNoteHooks, onProgress?: (percent: number) => void): Promise<string | null>;
7051
+ /**
7052
+ * 只读取合集某一项已持久化的明文资产并创建 object URL。
7053
+ *
7054
+ * 与 `loadCachedImageObjectUrl` 同一条合同:未缓存、下标越界、账号切换或缓存读取失败都返回 `null`,
7055
+ * 永不触发网络下载、不建下载任务、不显示用户提示,供预览器优先秒开已下载过的那一项。
7056
+ * 还在上传中的项地址是本地 `blob:`,不进这条路径——那一份要走 `acquireMediaBlob`。
7057
+ */
7058
+ declare function loadCachedMediaAlbumItemObjectUrl(runtime: ChatRuntime, message: ImMessageView, itemIndex: number): Promise<string | null>;
6679
7059
  /**
6680
7060
  * 下载并解密原图,校验真实图片格式后返回大图查看器可使用的临时地址。
6681
7061
  *
@@ -6701,22 +7081,28 @@ declare const media_service_acquireMediaBlob: typeof acquireMediaBlob;
6701
7081
  declare const media_service_detectImageMime: typeof detectImageMime;
6702
7082
  declare const media_service_detectVideoMime: typeof detectVideoMime;
6703
7083
  declare const media_service_loadCachedImageObjectUrl: typeof loadCachedImageObjectUrl;
7084
+ declare const media_service_loadCachedMediaAlbumItemObjectUrl: typeof loadCachedMediaAlbumItemObjectUrl;
6704
7085
  declare const media_service_loadCachedVideoObjectUrl: typeof loadCachedVideoObjectUrl;
6705
7086
  declare const media_service_loadFileObjectUrl: typeof loadFileObjectUrl;
6706
7087
  declare const media_service_loadImageObjectUrl: typeof loadImageObjectUrl;
7088
+ declare const media_service_loadMediaAlbumItemObjectUrl: typeof loadMediaAlbumItemObjectUrl;
6707
7089
  declare const media_service_loadVideoObjectUrl: typeof loadVideoObjectUrl;
6708
7090
  declare const media_service_loadVoiceBytes: typeof loadVoiceBytes;
7091
+ declare const media_service_prepareLocalMediaPreview: typeof prepareLocalMediaPreview;
6709
7092
  declare namespace media_service {
6710
7093
  export {
6711
7094
  media_service_acquireMediaBlob as acquireMediaBlob,
6712
7095
  media_service_detectImageMime as detectImageMime,
6713
7096
  media_service_detectVideoMime as detectVideoMime,
6714
7097
  media_service_loadCachedImageObjectUrl as loadCachedImageObjectUrl,
7098
+ media_service_loadCachedMediaAlbumItemObjectUrl as loadCachedMediaAlbumItemObjectUrl,
6715
7099
  media_service_loadCachedVideoObjectUrl as loadCachedVideoObjectUrl,
6716
7100
  media_service_loadFileObjectUrl as loadFileObjectUrl,
6717
7101
  media_service_loadImageObjectUrl as loadImageObjectUrl,
7102
+ media_service_loadMediaAlbumItemObjectUrl as loadMediaAlbumItemObjectUrl,
6718
7103
  media_service_loadVideoObjectUrl as loadVideoObjectUrl,
6719
7104
  media_service_loadVoiceBytes as loadVoiceBytes,
7105
+ media_service_prepareLocalMediaPreview as prepareLocalMediaPreview,
6720
7106
  };
6721
7107
  }
6722
7108
 
@@ -7184,6 +7570,13 @@ declare function fetchConversationVoiceBatch(runtime: ChatRuntime, input: Browse
7184
7570
  */
7185
7571
  declare function fetchNextConversationSearchBatch(runtime: ChatRuntime, pageToken: ImPageToken): Promise<SearchBatchResult>;
7186
7572
 
7573
+ type GifFileClassification = 'gif' | 'not-gif' | 'invalid-gif';
7574
+ /**
7575
+ * 同时核对 MIME 与文件头,避免 GIF 合同冲突的文件回落到普通 IMAGE 链路。
7576
+ *
7577
+ * 浏览器 MIME 可以为空;一旦 MIME 或文件头任一方声明 GIF,另一方就必须一致。
7578
+ */
7579
+ declare function classifyGifFile(file: Blob): Promise<GifFileClassification>;
7187
7580
  declare function isGifFile(file: Blob): Promise<boolean>;
7188
7581
 
7189
7582
  /**
@@ -7317,12 +7710,18 @@ declare function sendVoice(runtime: ChatRuntime, input: {
7317
7710
  conversationType: ConversationType | undefined;
7318
7711
  refMessageId?: string;
7319
7712
  }, hooks: SendCommandHooks): Promise<boolean>;
7320
- /**
7321
- * 批量发送用户选择的媒体,按 MIME 自动将每项识别为图片、视频或普通文件。
7322
- *
7323
- * 超过单批数量上限时只处理前 9 项并提示其余已跳过;随后按选择顺序创建独立消息,
7324
- * 实际文件读取与上传并发仍由 SDK 控制。
7325
- */
7713
+ declare function sendMediaAlbum(runtime: ChatRuntime, input: {
7714
+ items: readonly {
7715
+ kind: 'image' | 'video';
7716
+ file: File;
7717
+ localPreviewMetadata?: ImagePreviewMetadata | VideoPreviewMetadata;
7718
+ }[];
7719
+ conversationId: string;
7720
+ conversationType: ConversationType | undefined;
7721
+ caption?: string;
7722
+ hd?: boolean;
7723
+ refMessageId?: string;
7724
+ }, hooks: SendCommandHooks): Promise<boolean>;
7326
7725
  declare function sendMediaFilesBatch(runtime: ChatRuntime, input: {
7327
7726
  files: File[];
7328
7727
  conversationId: string;
@@ -8117,5 +8516,5 @@ declare function resampleWaveform(data: readonly number[], targetCount: number):
8117
8516
  */
8118
8517
  declare function placeholderWaveform(seed: string, count: number): number[];
8119
8518
 
8120
- export { DEFAULT_EMOJI_ASSET_BASE, DEFAULT_LOADING_MINIMUM_VISIBLE_MS, DEFAULT_LOADING_SHOW_DELAY_MS, EMOJI_CATALOG, EMOJI_GAME_DICE_STABLE_KEY, EMOJI_GAME_RPS_STABLE_KEY, EMOJI_TOKEN_RE, MAX_BATCH_FILES, MAX_RECENT_EMOJI_COUNT, SPIKE_STEP, UNICODE_EMOJI_CATALOG, blockReasonForChannelSession, blockReasonForChannelState, blockReasonForGroupState, blockReasonForSession, calculateMediaBox, canEditMessage, canPinChannelMessage, canPinGroupMessage, canPinMessage, canPromoteMediaPresentationSource, canRecallMessage, canTransmit, canTransmitByType, canTransmitContent, cancelMediaUpload, captureRuntimeClientOperation, captureRuntimeOperation, createChatRuntime, createDelayedLoadingIndicator, createEmojiMatcher, createLinkMatcher, createNewMessageBadgeController, createThreadItems, decideConversationAction, decideMemberTargetAction, decideMessageAction, emojiAssetUrl, emojiUrlByCode, fetchConversationFileBatch, fetchConversationImageBatch, fetchConversationMessageBatch, fetchConversationVideoBatch, fetchConversationVoiceBatch, fetchNextConversationSearchBatch, formatChatDateSeparator, formatConversationDisplayTime, formatFileSize, formatMediaDuration, forward_service as forwardService, getFileExtension, getLocalDayKey, hasEmojiCandidate, hasLinkCandidate, highlightSegments, isGifFile, isMessageLocateScrollProtected, isMessageTailChangeFromOlderWindowTrim, isMessageViewportMeasurable, isMessageVisibleForNewMessageBadge, isPinnedMessageProtected, isVoiceStorageConfigured, loadOlderUntilBoundary, mediaBatchBudgetBytes, media_service as mediaService, message_service as messageService, normalizeLinkHref, parseUnicodeEmojiCode, pinnedMessage_service as pinnedMessageService, placeholderWaveform, prependRecentEmoji, profile_service as profileService, read_service as readService, refreshPrependMessageAnchorPosition, replaceInterruptedMediaFile, requiresConversationEncryption, requiresForwardTypeConfirmation, resampleWaveform, resolveBestMediaPresentationSource, resolveCenteredMessageScrollTop, resolveChannelMemberAvatarUrl, resolveChannelMemberDisplayName, resolveConversationListPresentation, resolveDisplayTimestamp, resolveEmojiToken, resolveFriendDisplayName, resolveImProfileAccessDestination, resolveImThreadActiveDate, resolveMediaPresentation, resolveMemberDisplayName, resolveMessageBodyKind, resolveMessageTimelineTimestamp, resolvePrependMessageAnchor, resolvePrependMessageAnchorAdjustment, resolvePrependMessageAnchorPosition, resolvePublicNickname, resolveQuotedMessagePresentation, resolveSenderAvatarUrl, resolveStandaloneEmojiMessage, resolveSurvivingMessageAnchorAdjustment, resolveUnicodeEmoji, resolveVisibleMessageAnchorPositions, retryMessage, runMediaSendBatch, sendAsFilesBatch, sendBlockReasonForDecision, sendMediaFile, sendMediaFilesBatch, sendText, sendVoice, shouldCompleteInitialViewport, shouldFillInitialHistoryViewport, shouldFollowIncomingMessage, shouldLoadNewerHistoryPage, shouldPrefetchOlderHistory, shouldRestoreMessageViewportFocus, shouldShowChatDateSeparator, shouldTrackRemoteMessageForBadge, spikeCountForDuration, supportsConversationMention, unicodeEmojiTextFromCode };
8121
- export type { ApplySessionResult, BrowseMessagesInput, CanPinMessageInput, CenteredMessageScrollInput, ChatMediaMessageRef, ChatProfileAdapter, ChatRuntime, ChatRuntimeCredentials, ChatRuntimeFactories, ChatRuntimeHostDeps, ChatRuntimeOpResult, ConversationCapabilityAction, ConversationListPresentation, ConversationListPresentationLabels, ConversationListPresentationOptions, ConversationListPreviewSegment, ConversationSearchCategory, CreateThreadItemsInput, DelayedLoadingIndicator, DelayedLoadingIndicatorOptions, EmojiEntry, EmojiRecentItem, EmojiSegment, FormatTimeDisplayContext, ForwardCommandHooks, HighlightSegment, ImChannelMemberPresentation, ImChannelMentionPresentation, ImChannelProfilePresentation, ImForwardOperationResult, ImGroupMemberPresentation, ImMediaBatchSendResult, ImMessageActionResult, ImMessageBodyKind, ImMessageView, ImPinnedMessageActionResult, ImPinnedMessageSnapshot, ImProfileAccessDestination, ImQuotedMessagePresentation, ImTextResolver, ImThreadActiveDateSnapshot, ImThreadDateMarkerMetric, ImThreadDecoration, ImThreadEncryptionItem, ImThreadIntent, ImThreadItem, ImThreadPresentationAdapter, ImThreadReadActions, ImThreadReadTargetResolver, ImThreadViewportMetrics, IncomingMessageFollowInput, InitialHistoryViewportFillInput, InitialViewportCompletionInput, LinkSegment, MediaBatchBudgetOptions, MediaBatchLimitInfo, MediaLimitItem, MediaObjectUrlLease, MediaPresentationFit, MediaPresentationPolicy, MediaPresentationRule, MediaPresentationSourceCandidate, MediaPresentationSourceQuality, MediaSendBatchResult, MemberTargetCapabilityAction, MemberTargetCapabilityInput, MessageCapabilityAction, MessageCapabilityInput, MessageLocateScrollProtectionInput, NewMessageBadgeController, NewMessageBadgeCountListener, NewMessageBadgeVisibilityInput, NewerHistoryPageTriggerInput, OlderHistoryPrefetchInput, PrependAnchorCandidate, PrependAnchorViewport, PrependMessageAnchorPosition, RemoteMessageBadgeTrackingInput, ResolveMediaPresentationInput, ResolvedMediaPresentation, RichExtraSegment, RuntimeClientOperation, RuntimeOperation, SearchBatchResult, SearchFilesInput, SearchMessagesInput, SearchTextMessagesInput, SendCapabilityMode, SendCommandHooks, SendVoicePayload, SenderProfileEntry, ServiceNoteHooks, StandaloneEmojiMessage, UnicodeEmojiEntry };
8519
+ export { DEFAULT_EMOJI_ASSET_BASE, DEFAULT_LOADING_MINIMUM_VISIBLE_MS, DEFAULT_LOADING_SHOW_DELAY_MS, EMOJI_CATALOG, EMOJI_GAME_DICE_STABLE_KEY, EMOJI_GAME_RPS_STABLE_KEY, EMOJI_TOKEN_RE, MAX_BATCH_FILES, MAX_RECENT_EMOJI_COUNT, SPIKE_STEP, UNICODE_EMOJI_CATALOG, blockReasonForChannelSession, blockReasonForChannelState, blockReasonForGroupState, blockReasonForSession, calculateMediaBox, canEditMessage, canPinChannelMessage, canPinGroupMessage, canPinMessage, canPromoteMediaPresentationSource, canRecallMessage, canTransmit, canTransmitByType, canTransmitContent, cancelMediaUpload, captureRuntimeClientOperation, captureRuntimeOperation, classifyGifFile, createChatRuntime, createDelayedLoadingIndicator, createEmojiMatcher, createLinkMatcher, createNewMessageBadgeController, createThreadItems, decideConversationAction, decideMemberTargetAction, decideMessageAction, emojiAssetUrl, emojiUrlByCode, fetchConversationFileBatch, fetchConversationImageBatch, fetchConversationMessageBatch, fetchConversationVideoBatch, fetchConversationVoiceBatch, fetchNextConversationSearchBatch, formatChatDateSeparator, formatConversationDisplayTime, formatFileSize, formatMediaDuration, forward_service as forwardService, getFileExtension, getLocalDayKey, hasEmojiCandidate, hasLinkCandidate, highlightSegments, isGifFile, isMessageLocateScrollProtected, isMessageTailChangeFromOlderWindowTrim, isMessageViewportMeasurable, isMessageVisibleForNewMessageBadge, isPinnedMessageProtected, isVoiceStorageConfigured, loadOlderUntilBoundary, mediaBatchBudgetBytes, media_service as mediaService, message_service as messageService, normalizeLinkHref, parseUnicodeEmojiCode, pinnedMessage_service as pinnedMessageService, placeholderWaveform, prependRecentEmoji, profile_service as profileService, read_service as readService, refreshPrependMessageAnchorPosition, replaceInterruptedMediaFile, requiresConversationEncryption, requiresForwardTypeConfirmation, resampleWaveform, resolveBestMediaPresentationSource, resolveCenteredMessageScrollTop, resolveChannelMemberAvatarUrl, resolveChannelMemberDisplayName, resolveConversationListPresentation, resolveDisplayTimestamp, resolveEmojiToken, resolveFriendDisplayName, resolveImProfileAccessDestination, resolveImThreadActiveDate, resolveMediaPresentation, resolveMemberDisplayName, resolveMessageBodyKind, resolveMessageNotificationDecision, resolveMessageTimelineTimestamp, resolvePrependMessageAnchor, resolvePrependMessageAnchorAdjustment, resolvePrependMessageAnchorPosition, resolvePublicNickname, resolveQuotedMessagePresentation, resolveSenderAvatarUrl, resolveStandaloneEmojiMessage, resolveSurvivingMessageAnchorAdjustment, resolveUnicodeEmoji, resolveVisibleMessageAnchorPositions, retryMessage, runMediaSendBatch, sendAsFilesBatch, sendBlockReasonForDecision, sendMediaAlbum, sendMediaFile, sendMediaFilesBatch, sendText, sendVoice, shouldCompleteInitialViewport, shouldFillInitialHistoryViewport, shouldFollowIncomingMessage, shouldLoadNewerHistoryPage, shouldPrefetchOlderHistory, shouldRestoreMessageViewportFocus, shouldShowChatDateSeparator, shouldTrackRemoteMessageForBadge, spikeCountForDuration, supportsConversationMention, unicodeEmojiTextFromCode };
8520
+ export type { ApplySessionResult, BrowseMessagesInput, CanPinMessageInput, CenteredMessageScrollInput, ChatMediaMessageRef, ChatProfileAdapter, ChatRuntime, ChatRuntimeCredentials, ChatRuntimeFactories, ChatRuntimeHostDeps, ChatRuntimeOpResult, ConversationCapabilityAction, ConversationListPresentation, ConversationListPresentationLabels, ConversationListPresentationOptions, ConversationListPreviewMediaKind, ConversationListPreviewSegment, ConversationSearchCategory, CreateThreadItemsInput, DelayedLoadingIndicator, DelayedLoadingIndicatorOptions, EmojiEntry, EmojiRecentItem, EmojiSegment, FormatTimeDisplayContext, ForwardCommandHooks, GifFileClassification, HighlightSegment, ImChannelMemberPresentation, ImChannelMentionPresentation, ImChannelProfilePresentation, ImForwardOperationResult, ImGroupMemberPresentation, ImMediaBatchSendResult, ImMessageActionResult, ImMessageBodyKind, ImMessageView, ImPinnedMessageActionResult, ImPinnedMessageSnapshot, ImProfileAccessDestination, ImQuotedMessagePresentation, ImTextResolver, ImThreadActiveDateSnapshot, ImThreadDateMarkerMetric, ImThreadDecoration, ImThreadEncryptionItem, ImThreadIntent, ImThreadItem, ImThreadPresentationAdapter, ImThreadReadActions, ImThreadReadTargetResolver, ImThreadViewportMetrics, IncomingMessageFollowInput, InitialHistoryViewportFillInput, InitialViewportCompletionInput, LinkSegment, MediaBatchBudgetOptions, MediaBatchLimitInfo, MediaLimitItem, MediaObjectUrlLease, MediaPresentationFit, MediaPresentationPolicy, MediaPresentationRule, MediaPresentationSourceCandidate, MediaPresentationSourceQuality, MediaSendBatchResult, MemberTargetCapabilityAction, MemberTargetCapabilityInput, MessageCapabilityAction, MessageCapabilityInput, MessageLocateScrollProtectionInput, MessageNotificationDecision, MessageNotificationInput, NewMessageBadgeController, NewMessageBadgeCountListener, NewMessageBadgeVisibilityInput, NewerHistoryPageTriggerInput, OlderHistoryPrefetchInput, PrependAnchorCandidate, PrependAnchorViewport, PrependMessageAnchorPosition, RemoteMessageBadgeTrackingInput, ResolveMediaPresentationInput, ResolvedMediaPresentation, RichExtraSegment, RuntimeClientOperation, RuntimeOperation, SearchBatchResult, SearchFilesInput, SearchMessagesInput, SearchTextMessagesInput, SendCapabilityMode, SendCommandHooks, SendVoicePayload, SenderProfileEntry, ServiceNoteHooks, StandaloneEmojiMessage, UnicodeEmojiEntry };