k2-im 0.1.29 → 0.1.31

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.
package/dist/browser.js CHANGED
@@ -1 +1 @@
1
- export{A as createLazyBrowserApiProtocolClient}from'./chunk-TKWU3IO7.js';import'./chunk-XICYFDN4.js';import'./chunk-WOT6VMZA.js';
1
+ export{B as createLazyBrowserApiProtocolClient}from'./chunk-SMWPQSGR.js';import'./chunk-CIY4WBFJ.js';import'./chunk-WOT6VMZA.js';
@@ -4,8 +4,8 @@ import { Pinia, Store } from 'pinia';
4
4
  /** 媒体业务类型:实现据此选对象存储逻辑桶;sticker 对应 app-sticker。 */
5
5
  type MediaKind = 'image' | 'video' | 'voice' | 'file' | 'sticker';
6
6
 
7
- /** 会话类型。P0 只用 direct / group。 */
8
- type ConversationType = 'direct' | 'group' | 'channel' | 'supergroup';
7
+ /** 会话类型。P0 只用 direct / group;`robot` 是独立私聊 sibling,不得并入 direct。 */
8
+ type ConversationType = 'direct' | 'group' | 'channel' | 'supergroup' | 'robot';
9
9
  /**
10
10
  * 会话复合身份;`conversationId` 只在对应 `conversationType` 的领域内唯一。
11
11
  *
@@ -42,8 +42,8 @@ interface ConversationDraft$1 {
42
42
  attachments: readonly [];
43
43
  updatedAt: number;
44
44
  }
45
- /** 消息内容类型。sticker=表情/贴图(BMessage contentType=7);call=单聊通话记录(contentType=10);transfer=转账(contentType=16);robot=机器人卡片(contentType=18);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' | 'mediaAlbum' | 'robot' | 'unknown';
45
+ /** 消息内容类型。sticker=表情/贴图(BMessage contentType=7);call=单聊通话记录(contentType=10);transfer=转账(contentType=16);gift=礼品/刮刮卡(contentType=17);robot=机器人卡片(contentType=18);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' | 'gift' | 'call' | 'redPacket' | 'mediaAlbum' | 'robot' | 'unknown';
47
47
  /**
48
48
  * 发送态(客户端态):消息从本地创建到服务端确认的生命周期。
49
49
  * `uploading` 仅媒体消息使用:文件上传阶段(uploading→pending→sending→sent);
@@ -112,6 +112,8 @@ type LastMessageSummary = {
112
112
  gameType: ImGameType;
113
113
  } | {
114
114
  kind: 'transfer';
115
+ } | {
116
+ kind: 'gift';
115
117
  } | {
116
118
  kind: 'call';
117
119
  callKind: ImCallKind;
@@ -311,13 +313,14 @@ type ImGameBody = {
311
313
  * - `default`:0,普通可点卡片
312
314
  * - `board-game`:1,棋牌样式且不可点
313
315
  * - `board-game-link`:2,棋牌样式且可点
316
+ * - `game-preview`:3,气泡内嵌游戏预览 WebView
314
317
  * - `unknown`:必须同时保留 `rawShowType`,不得猜成可点/不可点
315
318
  */
316
- type ImMiniProgramShowType = 'default' | 'board-game' | 'board-game-link' | 'unknown';
319
+ type ImMiniProgramShowType = 'default' | 'board-game' | 'board-game-link' | 'game-preview' | 'unknown';
317
320
  /**
318
321
  * 小程序分享卡片正文(contentType==='miniProgram',协议 BMessage.contentType=22)。
319
322
  *
320
- * @remarks 字段来自 iOS `IMMiniProgramMessageBody` / proto 61-67、80-82、90-93。
323
+ * @remarks 字段来自 iOS `IMMiniProgramMessageBody` / proto 61-67、80-82、90-96。
321
324
  * `currencySource` 对应 proto field 90(无 miniProgram 前缀):`xj` 现金公司、`xy` 信用公司。
322
325
  * `subGameName` 保持服务端 JSON 字符串,不在 Core 解析语种表。打开小程序与 X 币/信用 ID 属于宿主,不进本 DTO。
323
326
  */
@@ -341,6 +344,12 @@ interface ImMiniProgramBody {
341
344
  gamePath?: string;
342
345
  /** 多语言子游戏名 JSON 字符串,例如 `{"ch":"...","en":"..."}`。 */
343
346
  subGameName?: string;
347
+ /** 游戏预览页地址(BMessage.miniProgramGamePreviewUrl,showType=3)。 */
348
+ gamePreviewUrl?: string;
349
+ /** 游戏预览设计宽(BMessage.miniProgramGamePreviewWidth)。 */
350
+ gamePreviewWidth?: number;
351
+ /** 游戏预览设计高(BMessage.miniProgramGamePreviewHeight)。 */
352
+ gamePreviewHeight?: number;
344
353
  }
345
354
  /**
346
355
  * 机器人卡片文本模块(wire `section`)。
@@ -419,6 +428,40 @@ interface ImTransferBody {
419
428
  coinName?: string;
420
429
  coinIcon?: string;
421
430
  }
431
+ /** 礼品类型。协议注释为刮刮卡 1 / 奖品 2;Android 当前会把 WelfareGiftType=0 写进消息,入站必须接受 0。 */
432
+ type ImGiftType = 0 | 1 | 2;
433
+ /** 礼品状态。0 待领取 / 1 已收款 / 2 已退还 / 3 已过期(对齐 iOS IMGiftMessageBody)。 */
434
+ type ImGiftStatus = 0 | 1 | 2 | 3;
435
+ /** 礼品会话类型。1 个人 / 2 群(BMessage.sessionType)。 */
436
+ type ImGiftSessionType = 1 | 2;
437
+ /**
438
+ * 礼品卡片正文(contentType==='gift',协议 BMessage.contentType=17)。
439
+ *
440
+ * @remarks 字段来自 iOS `IMGiftMessageBody` / proto 51-59,并复用转账字段族的 fromUid/toUid/serialNumber。
441
+ * 赠卡 HTTP 属于宿主;本 DTO 只承载会话卡片。H5 出站刮刮卡写 giftType=1。
442
+ */
443
+ interface ImGiftBody {
444
+ fromUid: string;
445
+ toUid: string;
446
+ fromUserName?: string;
447
+ toUserName?: string;
448
+ giftType: ImGiftType;
449
+ giftName: string;
450
+ giftIcon?: string;
451
+ explain?: string;
452
+ state: ImGiftStatus;
453
+ serialNumber: string;
454
+ sessionType: ImGiftSessionType;
455
+ initiateTime: number;
456
+ /** 单张金额的十进制字符串;0 或缺省表示未带金额。 */
457
+ amount?: string;
458
+ receiveTime?: number;
459
+ returnTime?: number;
460
+ isRead?: boolean;
461
+ zhangCount?: string;
462
+ benCount?: string;
463
+ fissionNumber?: string;
464
+ }
422
465
  /** 领域通话媒体类型;已从各端 wire 0/1 对调口径归一,宿主禁止再读 raw callType。 */
423
466
  type ImCallKind = 'audio' | 'video';
424
467
  /**
@@ -577,6 +620,8 @@ interface ImMessageBody {
577
620
  game?: ImGameBody;
578
621
  /** contentType==='transfer' 时的转账卡片。 */
579
622
  transfer?: ImTransferBody;
623
+ /** contentType==='gift' 时的礼品/刮刮卡卡片。 */
624
+ gift?: ImGiftBody;
580
625
  /** contentType==='call' 时的单聊通话记录。 */
581
626
  call?: ImCallRecordBody;
582
627
  /** contentType==='redPacket' 时的红包卡片。 */
@@ -965,7 +1010,7 @@ interface OutboxMessage {
965
1010
  resumePolicy?: 'automatic' | 'manual';
966
1011
  }
967
1012
  /** 当前 SDK 已注册发送策略、因此可作为转发目标的会话类型;supergroup 未注册,继续在编译期排除。 */
968
- type ForwardTargetConversationType = Extract<ConversationType, 'direct' | 'group' | 'channel'>;
1013
+ type ForwardTargetConversationType = Extract<ConversationType, 'direct' | 'group' | 'channel' | 'robot'>;
969
1014
  /** 转发目标会话;运行时仍由 SendStrategyRegistry 复核,避免类型声明与实际装配漂移。 */
970
1015
  interface ForwardTarget {
971
1016
  conversationId: string;
@@ -1852,6 +1897,44 @@ interface ImSessionFavoritePort {
1852
1897
  delete: (collectIds: readonly string[]) => Promise<void>;
1853
1898
  }
1854
1899
 
1900
+ /**
1901
+ * SDK 已取得的最近一页请求结果;只是可重建缓存,不代表消息已进入 DomainState 或处理过入站副作用。
1902
+ * 消息、Reaction 与分页边界必须整页原子保存,只有前台实际消费时才进入正常消息流程。
1903
+ */
1904
+ interface ImRecentHistoryPage {
1905
+ /**
1906
+ * 缓存记录格式版本;不认识的版本不能当作有效页使用。
1907
+ * v2:小程序 showType=3 / proto 94-96 进入领域正文,旧页必须重新拉网解析。
1908
+ */
1909
+ version: 2;
1910
+ /** 当前账号内的精确 GROUP/CHANNEL 会话;direct 没有此远端最近页能力。 */
1911
+ conversation: ConversationRef<'group' | 'channel'>;
1912
+ /** 成功获取页面的毫秒时间,用于保留期限和按获取时间淘汰。 */
1913
+ fetchedAt: number;
1914
+ /** SDK 生成的请求与会话状态指纹;存储层不解释其内容。 */
1915
+ fingerprint: string;
1916
+ /** 已净化的消息事实,缓存保存不得发布消息或已读事件。 */
1917
+ messages: readonly ImMessage[];
1918
+ /** 解码时暂存的 Reaction 事实,预取阶段不得提前应用。 */
1919
+ reactions: readonly ImReactionEvent[];
1920
+ /** 服务端是否明确没有更早一页,空页也保留这一结果。 */
1921
+ exhausted: boolean;
1922
+ /** 服务端返回的向旧游标,存储层仅原样保存。 */
1923
+ nextCursor?: string;
1924
+ /** SDK 按净化后的整页计算的字节数,用于存储预算。 */
1925
+ byteLength: number;
1926
+ }
1927
+ /** 账号隔离的最近页缓存;过期、淘汰或清理后重新请求即可,不影响消息真相。 */
1928
+ interface ImRecentHistoryCachePort {
1929
+ /** 读取精确会话的整页;不存在或超过保留期限时返回 null。 */
1930
+ get: (conversation: ConversationRef<'group' | 'channel'>) => Promise<ImRecentHistoryPage | null>;
1931
+ /** 原子保存整页;仅 durable 事务提交后返回 true,预算或保留期限不允许时返回 false。 */
1932
+ put: (page: ImRecentHistoryPage) => Promise<boolean>;
1933
+ /** 删除精确会话的缓存页,不删除正常历史或会话。 */
1934
+ delete: (conversation: ConversationRef<'group' | 'channel'>) => Promise<void>;
1935
+ /** 清空当前账号的最近页缓存。 */
1936
+ clear: () => Promise<void>;
1937
+ }
1855
1938
  /** 迁移期存储会话入参;新代码使用 ref,string 仅兼容唯一命中的旧调用。 */
1856
1939
  type ImStorageConversation = ConversationRef | string;
1857
1940
  /** 打开账号库的选项。namespace = 账号隔离键(登录 userId)。 */
@@ -2000,6 +2083,8 @@ type StoredConversationBackground = {
2000
2083
  * 失败经 `error` 事件(scope:'storage')暴露、不静默吞、不阻塞内存主流程。
2001
2084
  */
2002
2085
  interface ImStoragePort {
2086
+ /** 可选的最近页持久缓存;缺少该能力时 SDK 必须明确跳过持久预取。 */
2087
+ recentHistoryCache?: ImRecentHistoryCachePort;
2003
2088
  /** 打开/创建账号库并跑迁移(幂等)。open 前的读写应视为未就绪并抛错(不静默兜底)。 */
2004
2089
  open: (options: ImStorageOpenOptions) => Promise<void>;
2005
2090
  /** 关闭库句柄(登出/切账号)。 */
@@ -2161,6 +2246,10 @@ interface ImStoragePort {
2161
2246
  type ImEvent = {
2162
2247
  type: 'connection:changed';
2163
2248
  state: ImConnectionState;
2249
+ }
2250
+ /** 同账号已由另一个浏览器页面接管;本页会话不可复用,但宿主登录仍有效。 */
2251
+ | {
2252
+ type: 'session:replaced';
2164
2253
  } | {
2165
2254
  type: 'message:received';
2166
2255
  message: ImMessage;
@@ -2783,10 +2872,11 @@ interface MediaTransferAdapterConfig {
2783
2872
  */
2784
2873
  rangeDownload?: boolean;
2785
2874
  /**
2786
- * 媒体发送阶段的并发上限;由 im-core 消费,adapter 本身仍只负责单个上传任务。
2875
+ * 媒体发送阶段的并发上限;由 im-core 消费,限制媒体任务数而非分片请求数。
2787
2876
  *
2788
- * 并发按媒体体积分两档:图片与不超过分片阈值(16 MiB)的小文件走单次 PutObject、不占分片缓冲,
2789
- * 缺省 5;视频与超过阈值(或字节数未知)的文件走分片,每路各带分片缓冲,缺省 3。
2877
+ * 并发按媒体体积分两档:不超过分片阈值(16 MiB)的非视频媒体走小文件档,
2878
+ * 缺省 5;视频与超过阈值(或字节数未知)的内容走大文件档,缺省 3。
2879
+ * 分档只限制媒体任务数;实际 PUT/UploadPart 另受 adapter 的六路数据请求限制。
2790
2880
  * 两档都只接受 1-6 的整数,超出范围由 core 显式报错。
2791
2881
  * - 传一个数字:所有媒体共用这一个并发数,与分档前的语义一致。
2792
2882
  * - 传 `{ total, largeFiles }`:显式分档,`largeFiles` 不得超过 `total`。
@@ -2835,8 +2925,8 @@ interface IndexedDbStorageAdapterOptions {
2835
2925
  maxPendingWriteBytes?: number;
2836
2926
  };
2837
2927
  }
2838
- /** 官方浏览器 adapter 始终提供完整背景持久化能力;可选只存在于通用 `ImStoragePort` 兼容边界。 */
2839
- type IndexedDbStorageAdapter = ImStoragePort & MediaAssetCachePort & Required<Pick<ImStoragePort, 'getConversationBackground' | 'saveConversationBackground' | 'deleteConversationBackground' | 'getDefaultConversationBackground' | 'saveDefaultConversationBackground' | 'deleteDefaultConversationBackground'>>;
2928
+ /** 官方浏览器 adapter 始终提供背景和最近历史缓存;可选只存在于通用 `ImStoragePort` 兼容边界。 */
2929
+ type IndexedDbStorageAdapter = ImStoragePort & MediaAssetCachePort & Required<Pick<ImStoragePort, 'getConversationBackground' | 'recentHistoryCache' | 'saveConversationBackground' | 'deleteConversationBackground' | 'getDefaultConversationBackground' | 'saveDefaultConversationBackground' | 'deleteDefaultConversationBackground'>>;
2840
2930
  /**
2841
2931
  * 创建 IndexedDB 存储 adapter(实现 ImStoragePort)。
2842
2932
  * 生命周期:先 `open({ namespace })`(幂等,跑 schema 迁移),再读写;`close()` 释放句柄。
@@ -3027,6 +3117,10 @@ interface MiniProgramMessageOptions {
3027
3117
  interface TransferMessageOptions {
3028
3118
  replyToMessageId?: string;
3029
3119
  }
3120
+ /** 礼品卡片发送选项;正文必须已含福利中心赠送后的流水号与卡面。 */
3121
+ interface GiftMessageOptions {
3122
+ replyToMessageId?: string;
3123
+ }
3030
3124
  /**
3031
3125
  * 媒体合集里的一项:一张图片或一个视频。
3032
3126
  *
@@ -3438,6 +3532,21 @@ interface ImContactApi extends ImDirectoryApi<'individual'> {
3438
3532
  deleteFriendship: (userId: string) => Promise<void>;
3439
3533
  }
3440
3534
 
3535
+ /** 后台最近页预取的取消条件;取消不影响正在复用同一请求的前台会话。 */
3536
+ interface ConversationPrefetchOptions {
3537
+ signal?: AbortSignal;
3538
+ }
3539
+ /**
3540
+ * 单个会话的后台预取结果。ready 只在完整页面已写入当前账号缓存后返回。
3541
+ * skipped 表示当前类型、权限、存储或预算不允许预取;失败不改变正常打开会话的行为。
3542
+ */
3543
+ interface ConversationPrefetchResult {
3544
+ ref: ConversationRef<'direct' | 'group' | 'channel' | 'robot'>;
3545
+ status: 'ready' | 'skipped' | 'failed' | 'cancelled';
3546
+ reason?: 'unsupported' | 'unavailable' | 'storage-unavailable' | 'budget' | 'page-too-large' | 'decrypt-failed' | 'invalidated' | 'cancelled';
3547
+ error?: ImSdkErrorShape;
3548
+ }
3549
+
3441
3550
  /**
3442
3551
  * 当前账号草稿的产品 DTO、跨组件 API 与 handle 绑定门面。
3443
3552
  * 草稿按复合会话身份串行持久化,SDK DomainState 是唯一真相;附件尚未闭合时非空输入明确拒绝。
@@ -3475,7 +3584,7 @@ interface ConversationDraftApi {
3475
3584
  subscribe: (listener: (draft: ConversationDraft | null) => void) => () => void;
3476
3585
  }
3477
3586
  /**
3478
- * 当前账号的跨组件草稿 API;所有动作都要求 direct/GROUP/CHANNEL 精确复合身份。
3587
+ * 当前账号的跨组件草稿 API;所有动作都要求 direct / GROUP / CHANNEL / robot 精确复合身份。
3479
3588
  *
3480
3589
  * @example
3481
3590
  * ```ts
@@ -3499,11 +3608,11 @@ interface ImDraftsApi {
3499
3608
 
3500
3609
  /**
3501
3610
  * SDK 会话列表内部 sibling 路由与会话级写动作。
3502
- * 置顶、免打扰、已读和本地删除都要求精确 `ConversationRef`,并按 direct/GROUP/CHANNEL 独立协议分流。
3611
+ * 置顶、免打扰、已读和本地删除都要求精确 `ConversationRef`,并按 direct/GROUP/CHANNEL/robot 独立协议分流。
3503
3612
  */
3504
3613
 
3505
3614
  /** 当前兼容门面支持的精确会话 ref。 */
3506
- type ImSupportedConversationRef = ConversationRef<'direct' | 'group' | 'channel'>;
3615
+ type ImSupportedConversationRef = ConversationRef<'direct' | 'group' | 'channel' | 'robot'>;
3507
3616
  /**
3508
3617
  * 会话 API 的迁移期入参。优先传完整 ref;旧 string 仅在当前 session 中唯一命中时可用。
3509
3618
  *
@@ -3527,6 +3636,8 @@ interface ImConversationsApi {
3527
3636
  pullOffline: () => Promise<ImMessage[]>;
3528
3637
  /** 运行 direct/GROUP/CHANNEL sibling 离线同步。 */
3529
3638
  sync: () => Promise<void>;
3639
+ /** 静默准备最近页;结果成功表示当前账号缓存事务已提交。 */
3640
+ prefetchRecent: (refs: readonly ImSupportedConversationRef[], options?: ConversationPrefetchOptions) => Promise<readonly ConversationPrefetchResult[]>;
3530
3641
  /** 聚合总未读;默认排除 muted 会话。 */
3531
3642
  getTotalUnread: (options?: {
3532
3643
  includeMuted?: boolean;
@@ -3900,7 +4011,7 @@ interface ImDirectCallsApi {
3900
4011
  * Blob 只经 storage 持久化。异步读取使用运行时代际防止切会话/切账号晚返回,宿主负责最终渲染与 URL 释放。
3901
4012
  */
3902
4013
 
3903
- type ConversationBackgroundConversationType = 'direct' | 'group' | 'channel';
4014
+ type ConversationBackgroundConversationType = 'direct' | 'group' | 'channel' | 'robot';
3904
4015
  interface ConversationBackgroundPreset {
3905
4016
  id: string;
3906
4017
  url: string;
@@ -4060,7 +4171,7 @@ interface ImChannelProfile {
4060
4171
  */
4061
4172
 
4062
4173
  /** default 会话列表支持的精确类型;`supergroup` 继续受产品 Gate 约束。 */
4063
- type ProductConversationListType = 'direct' | 'group' | 'channel';
4174
+ type ProductConversationListType = 'direct' | 'group' | 'channel' | 'robot';
4064
4175
  /** GROUP 会话限制状态;与 CHANNEL 状态保持独立 sibling。 */
4065
4176
  type ImGroupConversationState = GroupSessionState;
4066
4177
  /**
@@ -4119,6 +4230,8 @@ type ConversationLastMessageSummary = {
4119
4230
  kind: 'robot';
4120
4231
  } | {
4121
4232
  kind: 'transfer';
4233
+ } | {
4234
+ kind: 'gift';
4122
4235
  } | {
4123
4236
  kind: 'redPacket';
4124
4237
  } | {
@@ -4232,6 +4345,8 @@ interface ImConversationListApi extends ImConversationBackgroundApi {
4232
4345
  subscribe: (listener: (snapshot: ImConversationListSnapshot) => void) => () => void;
4233
4346
  /** 显式运行 direct/GROUP/CHANNEL sibling 同步;失败抛稳定产品错误并进入 error 快照。 */
4234
4347
  refresh: () => Promise<void>;
4348
+ /** 静默预取各会话最近一页;不激活线程,ready 只表示持久缓存已完成。 */
4349
+ prefetchRecent: (refs: readonly ConversationRef<ProductConversationListType>[], options?: ConversationPrefetchOptions) => Promise<readonly ConversationPrefetchResult[]>;
4235
4350
  /** 读取总未读;默认排除 muted 会话。 */
4236
4351
  getTotalUnread: (options?: {
4237
4352
  includeMuted?: boolean;
@@ -4272,6 +4387,12 @@ interface DirectConversationCapabilities {
4272
4387
  canUseMessageActions: CapabilityDecision;
4273
4388
  canManageRelationship: CapabilityDecision;
4274
4389
  }
4390
+ interface RobotConversationCapabilities {
4391
+ canSendMessages: CapabilityDecision;
4392
+ canOpenProfile: CapabilityDecision;
4393
+ canUseMessageActions: CapabilityDecision;
4394
+ canReadHistory: CapabilityDecision;
4395
+ }
4275
4396
  /**
4276
4397
  * 普通群能力快照。
4277
4398
  *
@@ -4338,6 +4459,8 @@ type ConversationCapabilitySnapshot = (ConversationCapabilityBase<'direct'> & {
4338
4459
  value: GroupConversationCapabilities;
4339
4460
  }) | (ConversationCapabilityBase<'channel'> & {
4340
4461
  value: ChannelConversationCapabilities;
4462
+ }) | (ConversationCapabilityBase<'robot'> & {
4463
+ value: RobotConversationCapabilities;
4341
4464
  });
4342
4465
  interface ImConversationCapabilitiesApi {
4343
4466
  /** 只读取 SDK 当前本机真相与已刷新过的资料/关系投影,不隐式联网。 */
@@ -4504,7 +4627,7 @@ interface ImMessagesByIdResult<TMessage> {
4504
4627
  */
4505
4628
 
4506
4629
  /** 当前已接线的产品 handle 会话类型;三者只在无会话语义原子层复用。 */
4507
- type ProductHandleConversationType = 'direct' | 'group' | 'channel';
4630
+ type ProductHandleConversationType = 'direct' | 'group' | 'channel' | 'robot';
4508
4631
  /**
4509
4632
  * 会话 handle 初始打开位置。
4510
4633
  *
@@ -4517,6 +4640,8 @@ type ConversationInitialPosition = 'latest' | 'first-unread';
4517
4640
  * @remarks 选项只影响初始连续窗口和 `entryUnread` 快照;发送、历史分页、已读和 close 语义保持不变。
4518
4641
  */
4519
4642
  interface ConversationOpenOptions {
4643
+ /** 取消尚未交付的会话打开及其历史请求;句柄交付后由 close 管理生命周期。 */
4644
+ signal?: AbortSignal;
4520
4645
  /**
4521
4646
  * 初始连续窗口位置。
4522
4647
  *
@@ -4637,6 +4762,12 @@ interface ConversationMessageApi {
4637
4762
  * @remarks CHANNEL 当前产品入口不发送转账,会返回 unsupported。消息固定明文。
4638
4763
  */
4639
4764
  sendTransfer: (transfer: ImTransferBody, options?: TransferMessageOptions) => Promise<SendMessageResult>;
4765
+ /**
4766
+ * 发送礼品卡片。调用方必须先完成福利中心 HTTP 赠送。
4767
+ *
4768
+ * @remarks CHANNEL 当前产品入口不发送礼物,会返回 unsupported。消息固定明文。
4769
+ */
4770
+ sendGift: (gift: ImGiftBody, options?: GiftMessageOptions) => Promise<SendMessageResult>;
4640
4771
  /** 当前用户已选相同 emoji 时移除,否则添加或替换。emoji 必须是协议 token,例如 `[Great]`。 */
4641
4772
  toggleReaction: (messageId: string, emoji: string) => Promise<ImReactionChangeResult>;
4642
4773
  /** 显式添加/替换或移除,供参与者详情等不能用 toggle 猜动作的产品交互。 */
@@ -5146,6 +5277,8 @@ interface ImProductEventMap {
5146
5277
  'connection:changed': Readonly<{
5147
5278
  snapshot: ImLifecycleSnapshot;
5148
5279
  }>;
5280
+ /** 另一个页面接管聊天;宿主可提示刷新此页重新接管,不应退出业务登录。 */
5281
+ 'session:replaced': Readonly<Record<never, never>>;
5149
5282
  'message:received': Readonly<{
5150
5283
  ref: ConversationRef<ProductConversationListType>;
5151
5284
  message: ImProductMessage;
@@ -5474,6 +5607,57 @@ interface ImRequestError {
5474
5607
  */
5475
5608
  type ImRequestErrorHandler = (issue: ImRequestError) => void | Promise<void>;
5476
5609
 
5610
+ /**
5611
+ * 机器人目录产品分页运行时。
5612
+ * 服务端页码封装为绑定账号 runtime 与查询条件的 opaque token;伪造、跨筛选或已消费 token 显式失败。
5613
+ */
5614
+
5615
+ /**
5616
+ * 机器人目录查询范围。
5617
+ *
5618
+ * `catalog` 对齐通讯录「查找机器人」;`conversation` 对齐群/社群资料添加与输入栏已绑定列表。
5619
+ */
5620
+ type ImRobotDirectoryScope = {
5621
+ kind: 'catalog';
5622
+ } | {
5623
+ kind: 'conversation';
5624
+ conversationType: 'group' | 'channel';
5625
+ conversationId: string;
5626
+ /** `bound` 对齐 iOS 输入栏 `search_type=1`。 */
5627
+ filter?: 'bound';
5628
+ };
5629
+ /** 机器人目录项;只保留打开私聊和列表展示所需字段。 */
5630
+ interface ImRobotDirectoryItem {
5631
+ id: string;
5632
+ displayName: string;
5633
+ username?: string;
5634
+ avatarUrl?: string;
5635
+ bound?: boolean;
5636
+ }
5637
+ /** 把机器人绑定或解绑到普通群/社群。 */
5638
+ interface ImRobotConversationBindInput {
5639
+ robotId: string;
5640
+ conversationType: 'group' | 'channel';
5641
+ conversationId: string;
5642
+ }
5643
+ /** 机器人目录页;服务端页码由 SDK token 封装,UI 只能原样续页。 */
5644
+ interface ImRobotDirectoryPage {
5645
+ items: readonly ImRobotDirectoryItem[];
5646
+ nextPageToken?: ImPageToken;
5647
+ exhausted: boolean;
5648
+ }
5649
+ /** 机器人目录产品分页面。 */
5650
+ interface ImRobotsApi {
5651
+ listFirstPage: (options?: {
5652
+ scope?: ImRobotDirectoryScope;
5653
+ keyword?: string;
5654
+ pageSize?: number;
5655
+ }) => Promise<ImRobotDirectoryPage>;
5656
+ listNextPage: (pageToken: ImPageToken) => Promise<ImRobotDirectoryPage>;
5657
+ bindToConversation: (input: ImRobotConversationBindInput) => Promise<void>;
5658
+ unbindFromConversation: (input: ImRobotConversationBindInput) => Promise<void>;
5659
+ }
5660
+
5477
5661
  /**
5478
5662
  * 当前账号本地会话与消息的分场景产品搜索运行时。
5479
5663
  *
@@ -5536,6 +5720,8 @@ interface ImMessageSearchApi {
5536
5720
  inGroup: (conversation: ConversationRef<'group'>, keyword: string) => Promise<ProductMessageSearchPage<MessageContentType>>;
5537
5721
  /** 搜索 CHANNEL 本地历史;当前不调用未闭合的远端 CHANNEL 搜索/定位协议。 */
5538
5722
  inChannel: (conversation: ConversationRef<'channel'>, keyword: string) => Promise<ProductMessageSearchPage<MessageContentType>>;
5723
+ /** 搜索 robot 本地历史;无远端历史,不得回退 direct。 */
5724
+ inRobot: (conversation: ConversationRef<'robot'>, keyword: string) => Promise<ProductMessageSearchPage<MessageContentType>>;
5539
5725
  /** 只搜索文本消息;关键词必填且不能为空。 */
5540
5726
  texts: (conversation: ConversationRef<ProductHandleConversationType>, keyword: string) => Promise<ProductMessageSearchPage<'text'>>;
5541
5727
  /** 只搜索文件消息;省略或传空白关键词时按文件分类浏览。 */
@@ -6065,7 +6251,7 @@ interface AdvancedConversationsApi extends ImConversationsApi, ImConversationBac
6065
6251
  *
6066
6252
  * @internal
6067
6253
  */
6068
- ensureOpenableConversation: (ref: ConversationRef) => Promise<ConversationRef<'direct' | 'group' | 'channel'>>;
6254
+ ensureOpenableConversation: (ref: ConversationRef) => Promise<ConversationRef<'direct' | 'group' | 'channel' | 'robot'>>;
6069
6255
  }
6070
6256
  /**
6071
6257
  * 普通宿主的真实 default client。
@@ -6089,6 +6275,8 @@ interface ImProductClient {
6089
6275
  readonly conversations: ImConversationListApi;
6090
6276
  /** 当前账号完整联系人、群组和社群目录的统一搜索。 */
6091
6277
  readonly directory: ImDirectorySearchApi;
6278
+ /** 机器人公开目录;通讯录查找与群/社群绑定列表共用分页合同。 */
6279
+ readonly robots: ImRobotsApi;
6092
6280
  readonly contacts: ImContactsApi;
6093
6281
  readonly groups: ImGroupsApi;
6094
6282
  readonly channels: ImChannelsApi;
@@ -6138,6 +6326,7 @@ interface ImClient extends Omit<ImProductClient, 'capabilities' | 'channels' | '
6138
6326
  (ref: ConversationRef<'direct'>, options?: ConversationOpenOptions): Promise<ConversationHandle<'direct'>>;
6139
6327
  (ref: ConversationRef<'group'>, options?: ConversationOpenOptions): Promise<ConversationHandle<'group'>>;
6140
6328
  (ref: ConversationRef<'channel'>, options?: ConversationOpenOptions): Promise<ConversationHandle<'channel'>>;
6329
+ (ref: ConversationRef<'robot'>, options?: ConversationOpenOptions): Promise<ConversationHandle<'robot'>>;
6141
6330
  };
6142
6331
  /** 当前账号草稿产品面;按复合身份持久化,handle.draft 委托同一状态源。 */
6143
6332
  drafts: ImDraftsApi;
@@ -6289,7 +6478,7 @@ declare function useImApplicationsStore(pinia?: Pinia): ImApplicationsStore;
6289
6478
  * 二期收敛:kit 框架无关层不再直接产中文,改产本联合里的码 + 参数(如 {reason}/{label}/{size}),由宿主经 im-i18n 渲染。
6290
6479
  * 动态原始报错(error.message)作为 `{reason}` 参数拼接,不入 catalog(属诊断,不翻译)。
6291
6480
  */
6292
- 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.imageFormatUnsupported' | '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';
6481
+ 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.imageFormatUnsupported' | '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' | 'lifecycle.connectionOccupied' | 'lifecycle.connectionCoordinationUnavailable' | 'forward.emptyInput' | 'forward.allSkipped' | 'forward.partialSkipped' | 'forward.done' | 'forward.failed';
6293
6482
 
6294
6483
  /**
6295
6484
  * 本文件管理图片和视频本地预览地址的完整生命周期。
@@ -6589,7 +6778,8 @@ interface ChatRuntime {
6589
6778
  /**
6590
6779
  * 在账号或 token 发生变化时,立即停止并清理旧账号运行资源。
6591
6780
  *
6592
- * 它会断开旧连接,关闭本机消息库,丢弃 SDK Client、资料缓存和媒体资源,并递增账号版本号;
6781
+ * 它会立即停止旧连接并丢弃页面资源,异步销毁 SDK Client、关闭消息库和释放浏览器锁;
6782
+ * 新 prepare/connect 等待清理完成,账号版本号同步递增;
6593
6783
  * 已注册的 Store 监听器会保留,以便新账号重新连接后继续接收事件。通常由 `applySession` 自动调用。
6594
6784
  */
6595
6785
  resetForAuthChange: () => void;
@@ -6650,7 +6840,7 @@ interface ChatRuntime {
6650
6840
  /** 撤销当前账号创建的全部媒体预览地址并释放 Blob 内存,切账号、退出或销毁时调用。 */
6651
6841
  cleanupLocalMediaBlobs: () => void;
6652
6842
  /** 删除会话时释放该会话绑定的本地媒体预览/播放缓存。 */
6653
- cleanupConversationMediaBlobs: (conversation: ConversationRef<'direct' | 'group' | 'channel'>) => void;
6843
+ cleanupConversationMediaBlobs: (conversation: ConversationRef<'direct' | 'group' | 'channel' | 'robot'>) => void;
6654
6844
  }
6655
6845
 
6656
6846
  /** 当前置顶消息的稳定资料;普通群和社群各自保留明确会话身份。 */
@@ -6996,6 +7186,8 @@ interface ImConversationListStore {
6996
7186
  readonly items: readonly ConversationListItem[];
6997
7187
  readonly state: ImConversationListState;
6998
7188
  readonly totalUnread: number;
7189
+ /** 菜单角标使用的非免打扰未读会话数;totalUnread 仍为 SDK 原始未读消息条数。 */
7190
+ readonly unreadConversationCount: number;
6999
7191
  readonly error: ImSdkErrorShape | null;
7000
7192
  start: () => void;
7001
7193
  reset: () => void;
@@ -7033,6 +7225,7 @@ declare function defineImConversationListStore(pinia: Pinia): pinia.StoreDefinit
7033
7225
  items: any;
7034
7226
  state: any;
7035
7227
  totalUnread: any;
7228
+ unreadConversationCount: any;
7036
7229
  error: any;
7037
7230
  start: () => void;
7038
7231
  reset: () => void;
@@ -7047,6 +7240,7 @@ declare function defineImConversationListStore(pinia: Pinia): pinia.StoreDefinit
7047
7240
  items: any;
7048
7241
  state: any;
7049
7242
  totalUnread: any;
7243
+ unreadConversationCount: any;
7050
7244
  error: any;
7051
7245
  start: () => void;
7052
7246
  reset: () => void;
@@ -7061,6 +7255,7 @@ declare function defineImConversationListStore(pinia: Pinia): pinia.StoreDefinit
7061
7255
  items: any;
7062
7256
  state: any;
7063
7257
  totalUnread: any;
7258
+ unreadConversationCount: any;
7064
7259
  error: any;
7065
7260
  start: () => void;
7066
7261
  reset: () => void;