k2-im 0.1.29 → 0.1.30

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-GHZUH7RB.js';import'./chunk-4KPJTXQN.js';import'./chunk-WOT6VMZA.js';
@@ -1852,6 +1852,41 @@ interface ImSessionFavoritePort {
1852
1852
  delete: (collectIds: readonly string[]) => Promise<void>;
1853
1853
  }
1854
1854
 
1855
+ /**
1856
+ * SDK 已取得的最近一页请求结果;只是可重建缓存,不代表消息已进入 DomainState 或处理过入站副作用。
1857
+ * 消息、Reaction 与分页边界必须整页原子保存,只有前台实际消费时才进入正常消息流程。
1858
+ */
1859
+ interface ImRecentHistoryPage {
1860
+ /** 缓存记录格式版本;不认识的版本不能当作有效页使用。 */
1861
+ version: 1;
1862
+ /** 当前账号内的精确 GROUP/CHANNEL 会话;direct 没有此远端最近页能力。 */
1863
+ conversation: ConversationRef<'group' | 'channel'>;
1864
+ /** 成功获取页面的毫秒时间,用于保留期限和按获取时间淘汰。 */
1865
+ fetchedAt: number;
1866
+ /** SDK 生成的请求与会话状态指纹;存储层不解释其内容。 */
1867
+ fingerprint: string;
1868
+ /** 已净化的消息事实,缓存保存不得发布消息或已读事件。 */
1869
+ messages: readonly ImMessage[];
1870
+ /** 解码时暂存的 Reaction 事实,预取阶段不得提前应用。 */
1871
+ reactions: readonly ImReactionEvent[];
1872
+ /** 服务端是否明确没有更早一页,空页也保留这一结果。 */
1873
+ exhausted: boolean;
1874
+ /** 服务端返回的向旧游标,存储层仅原样保存。 */
1875
+ nextCursor?: string;
1876
+ /** SDK 按净化后的整页计算的字节数,用于存储预算。 */
1877
+ byteLength: number;
1878
+ }
1879
+ /** 账号隔离的最近页缓存;过期、淘汰或清理后重新请求即可,不影响消息真相。 */
1880
+ interface ImRecentHistoryCachePort {
1881
+ /** 读取精确会话的整页;不存在或超过保留期限时返回 null。 */
1882
+ get: (conversation: ConversationRef<'group' | 'channel'>) => Promise<ImRecentHistoryPage | null>;
1883
+ /** 原子保存整页;仅 durable 事务提交后返回 true,预算或保留期限不允许时返回 false。 */
1884
+ put: (page: ImRecentHistoryPage) => Promise<boolean>;
1885
+ /** 删除精确会话的缓存页,不删除正常历史或会话。 */
1886
+ delete: (conversation: ConversationRef<'group' | 'channel'>) => Promise<void>;
1887
+ /** 清空当前账号的最近页缓存。 */
1888
+ clear: () => Promise<void>;
1889
+ }
1855
1890
  /** 迁移期存储会话入参;新代码使用 ref,string 仅兼容唯一命中的旧调用。 */
1856
1891
  type ImStorageConversation = ConversationRef | string;
1857
1892
  /** 打开账号库的选项。namespace = 账号隔离键(登录 userId)。 */
@@ -2000,6 +2035,8 @@ type StoredConversationBackground = {
2000
2035
  * 失败经 `error` 事件(scope:'storage')暴露、不静默吞、不阻塞内存主流程。
2001
2036
  */
2002
2037
  interface ImStoragePort {
2038
+ /** 可选的最近页持久缓存;缺少该能力时 SDK 必须明确跳过持久预取。 */
2039
+ recentHistoryCache?: ImRecentHistoryCachePort;
2003
2040
  /** 打开/创建账号库并跑迁移(幂等)。open 前的读写应视为未就绪并抛错(不静默兜底)。 */
2004
2041
  open: (options: ImStorageOpenOptions) => Promise<void>;
2005
2042
  /** 关闭库句柄(登出/切账号)。 */
@@ -2161,6 +2198,10 @@ interface ImStoragePort {
2161
2198
  type ImEvent = {
2162
2199
  type: 'connection:changed';
2163
2200
  state: ImConnectionState;
2201
+ }
2202
+ /** 同账号已由另一个浏览器页面接管;本页会话不可复用,但宿主登录仍有效。 */
2203
+ | {
2204
+ type: 'session:replaced';
2164
2205
  } | {
2165
2206
  type: 'message:received';
2166
2207
  message: ImMessage;
@@ -2783,10 +2824,11 @@ interface MediaTransferAdapterConfig {
2783
2824
  */
2784
2825
  rangeDownload?: boolean;
2785
2826
  /**
2786
- * 媒体发送阶段的并发上限;由 im-core 消费,adapter 本身仍只负责单个上传任务。
2827
+ * 媒体发送阶段的并发上限;由 im-core 消费,限制媒体任务数而非分片请求数。
2787
2828
  *
2788
- * 并发按媒体体积分两档:图片与不超过分片阈值(16 MiB)的小文件走单次 PutObject、不占分片缓冲,
2789
- * 缺省 5;视频与超过阈值(或字节数未知)的文件走分片,每路各带分片缓冲,缺省 3。
2829
+ * 并发按媒体体积分两档:不超过分片阈值(16 MiB)的非视频媒体走小文件档,
2830
+ * 缺省 5;视频与超过阈值(或字节数未知)的内容走大文件档,缺省 3。
2831
+ * 分档只限制媒体任务数;实际 PUT/UploadPart 另受 adapter 的六路数据请求限制。
2790
2832
  * 两档都只接受 1-6 的整数,超出范围由 core 显式报错。
2791
2833
  * - 传一个数字:所有媒体共用这一个并发数,与分档前的语义一致。
2792
2834
  * - 传 `{ total, largeFiles }`:显式分档,`largeFiles` 不得超过 `total`。
@@ -2835,8 +2877,8 @@ interface IndexedDbStorageAdapterOptions {
2835
2877
  maxPendingWriteBytes?: number;
2836
2878
  };
2837
2879
  }
2838
- /** 官方浏览器 adapter 始终提供完整背景持久化能力;可选只存在于通用 `ImStoragePort` 兼容边界。 */
2839
- type IndexedDbStorageAdapter = ImStoragePort & MediaAssetCachePort & Required<Pick<ImStoragePort, 'getConversationBackground' | 'saveConversationBackground' | 'deleteConversationBackground' | 'getDefaultConversationBackground' | 'saveDefaultConversationBackground' | 'deleteDefaultConversationBackground'>>;
2880
+ /** 官方浏览器 adapter 始终提供背景和最近历史缓存;可选只存在于通用 `ImStoragePort` 兼容边界。 */
2881
+ type IndexedDbStorageAdapter = ImStoragePort & MediaAssetCachePort & Required<Pick<ImStoragePort, 'getConversationBackground' | 'recentHistoryCache' | 'saveConversationBackground' | 'deleteConversationBackground' | 'getDefaultConversationBackground' | 'saveDefaultConversationBackground' | 'deleteDefaultConversationBackground'>>;
2840
2882
  /**
2841
2883
  * 创建 IndexedDB 存储 adapter(实现 ImStoragePort)。
2842
2884
  * 生命周期:先 `open({ namespace })`(幂等,跑 schema 迁移),再读写;`close()` 释放句柄。
@@ -3438,6 +3480,21 @@ interface ImContactApi extends ImDirectoryApi<'individual'> {
3438
3480
  deleteFriendship: (userId: string) => Promise<void>;
3439
3481
  }
3440
3482
 
3483
+ /** 后台最近页预取的取消条件;取消不影响正在复用同一请求的前台会话。 */
3484
+ interface ConversationPrefetchOptions {
3485
+ signal?: AbortSignal;
3486
+ }
3487
+ /**
3488
+ * 单个会话的后台预取结果。ready 只在完整页面已写入当前账号缓存后返回。
3489
+ * skipped 表示当前类型、权限、存储或预算不允许预取;失败不改变正常打开会话的行为。
3490
+ */
3491
+ interface ConversationPrefetchResult {
3492
+ ref: ConversationRef<'direct' | 'group' | 'channel'>;
3493
+ status: 'ready' | 'skipped' | 'failed' | 'cancelled';
3494
+ reason?: 'unsupported' | 'unavailable' | 'storage-unavailable' | 'budget' | 'page-too-large' | 'decrypt-failed' | 'invalidated' | 'cancelled';
3495
+ error?: ImSdkErrorShape;
3496
+ }
3497
+
3441
3498
  /**
3442
3499
  * 当前账号草稿的产品 DTO、跨组件 API 与 handle 绑定门面。
3443
3500
  * 草稿按复合会话身份串行持久化,SDK DomainState 是唯一真相;附件尚未闭合时非空输入明确拒绝。
@@ -3527,6 +3584,8 @@ interface ImConversationsApi {
3527
3584
  pullOffline: () => Promise<ImMessage[]>;
3528
3585
  /** 运行 direct/GROUP/CHANNEL sibling 离线同步。 */
3529
3586
  sync: () => Promise<void>;
3587
+ /** 静默准备最近页;结果成功表示当前账号缓存事务已提交。 */
3588
+ prefetchRecent: (refs: readonly ImSupportedConversationRef[], options?: ConversationPrefetchOptions) => Promise<readonly ConversationPrefetchResult[]>;
3530
3589
  /** 聚合总未读;默认排除 muted 会话。 */
3531
3590
  getTotalUnread: (options?: {
3532
3591
  includeMuted?: boolean;
@@ -4232,6 +4291,8 @@ interface ImConversationListApi extends ImConversationBackgroundApi {
4232
4291
  subscribe: (listener: (snapshot: ImConversationListSnapshot) => void) => () => void;
4233
4292
  /** 显式运行 direct/GROUP/CHANNEL sibling 同步;失败抛稳定产品错误并进入 error 快照。 */
4234
4293
  refresh: () => Promise<void>;
4294
+ /** 静默预取各会话最近一页;不激活线程,ready 只表示持久缓存已完成。 */
4295
+ prefetchRecent: (refs: readonly ConversationRef<ProductConversationListType>[], options?: ConversationPrefetchOptions) => Promise<readonly ConversationPrefetchResult[]>;
4235
4296
  /** 读取总未读;默认排除 muted 会话。 */
4236
4297
  getTotalUnread: (options?: {
4237
4298
  includeMuted?: boolean;
@@ -4517,6 +4578,8 @@ type ConversationInitialPosition = 'latest' | 'first-unread';
4517
4578
  * @remarks 选项只影响初始连续窗口和 `entryUnread` 快照;发送、历史分页、已读和 close 语义保持不变。
4518
4579
  */
4519
4580
  interface ConversationOpenOptions {
4581
+ /** 取消尚未交付的会话打开及其历史请求;句柄交付后由 close 管理生命周期。 */
4582
+ signal?: AbortSignal;
4520
4583
  /**
4521
4584
  * 初始连续窗口位置。
4522
4585
  *
@@ -5146,6 +5209,8 @@ interface ImProductEventMap {
5146
5209
  'connection:changed': Readonly<{
5147
5210
  snapshot: ImLifecycleSnapshot;
5148
5211
  }>;
5212
+ /** 另一个页面接管聊天;宿主可提示刷新此页重新接管,不应退出业务登录。 */
5213
+ 'session:replaced': Readonly<Record<never, never>>;
5149
5214
  'message:received': Readonly<{
5150
5215
  ref: ConversationRef<ProductConversationListType>;
5151
5216
  message: ImProductMessage;
@@ -6289,7 +6354,7 @@ declare function useImApplicationsStore(pinia?: Pinia): ImApplicationsStore;
6289
6354
  * 二期收敛:kit 框架无关层不再直接产中文,改产本联合里的码 + 参数(如 {reason}/{label}/{size}),由宿主经 im-i18n 渲染。
6290
6355
  * 动态原始报错(error.message)作为 `{reason}` 参数拼接,不入 catalog(属诊断,不翻译)。
6291
6356
  */
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';
6357
+ 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
6358
 
6294
6359
  /**
6295
6360
  * 本文件管理图片和视频本地预览地址的完整生命周期。
@@ -6589,7 +6654,8 @@ interface ChatRuntime {
6589
6654
  /**
6590
6655
  * 在账号或 token 发生变化时,立即停止并清理旧账号运行资源。
6591
6656
  *
6592
- * 它会断开旧连接,关闭本机消息库,丢弃 SDK Client、资料缓存和媒体资源,并递增账号版本号;
6657
+ * 它会立即停止旧连接并丢弃页面资源,异步销毁 SDK Client、关闭消息库和释放浏览器锁;
6658
+ * 新 prepare/connect 等待清理完成,账号版本号同步递增;
6593
6659
  * 已注册的 Store 监听器会保留,以便新账号重新连接后继续接收事件。通常由 `applySession` 自动调用。
6594
6660
  */
6595
6661
  resetForAuthChange: () => void;
@@ -6996,6 +7062,8 @@ interface ImConversationListStore {
6996
7062
  readonly items: readonly ConversationListItem[];
6997
7063
  readonly state: ImConversationListState;
6998
7064
  readonly totalUnread: number;
7065
+ /** 菜单角标使用的非免打扰未读会话数;totalUnread 仍为 SDK 原始未读消息条数。 */
7066
+ readonly unreadConversationCount: number;
6999
7067
  readonly error: ImSdkErrorShape | null;
7000
7068
  start: () => void;
7001
7069
  reset: () => void;
@@ -7033,6 +7101,7 @@ declare function defineImConversationListStore(pinia: Pinia): pinia.StoreDefinit
7033
7101
  items: any;
7034
7102
  state: any;
7035
7103
  totalUnread: any;
7104
+ unreadConversationCount: any;
7036
7105
  error: any;
7037
7106
  start: () => void;
7038
7107
  reset: () => void;
@@ -7047,6 +7116,7 @@ declare function defineImConversationListStore(pinia: Pinia): pinia.StoreDefinit
7047
7116
  items: any;
7048
7117
  state: any;
7049
7118
  totalUnread: any;
7119
+ unreadConversationCount: any;
7050
7120
  error: any;
7051
7121
  start: () => void;
7052
7122
  reset: () => void;
@@ -7061,6 +7131,7 @@ declare function defineImConversationListStore(pinia: Pinia): pinia.StoreDefinit
7061
7131
  items: any;
7062
7132
  state: any;
7063
7133
  totalUnread: any;
7134
+ unreadConversationCount: any;
7064
7135
  error: any;
7065
7136
  start: () => void;
7066
7137
  reset: () => void;