@typexim/web-sdk 0.0.5-alpha.9 → 0.0.7

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/README.md CHANGED
@@ -93,6 +93,7 @@ chat.once(
93
93
 
94
94
  1. joinRoom
95
95
  2. leaveRoom
96
+ 3. getJoinedRooms
96
97
 
97
98
  ### 聊天室Room消息
98
99
 
@@ -101,4 +102,4 @@ chat.once(
101
102
 
102
103
  ## 注意事项
103
104
 
104
- 1. 同个浏览器只有最先调用login成功的窗口可以正常使用,其他窗口要使用就得先在已登录的窗口调用logout或者关闭窗口
105
+ 1. 同个浏览器打开多个窗口时,新窗口会优先复用已登录窗口的登录态并接管 WebSocket 连接;旧窗口会触发 `SDK_NOT_READY`,无需先手动 logout 或关闭窗口。
@@ -36,6 +36,10 @@ export declare const CHAT_SDK_EVENT: {
36
36
  * sdk收到message已读回执
37
37
  */
38
38
  readonly MESSAGE_RECEIPT_RECEIVED: "messageReceiptReceived";
39
+ /***
40
+ * sdk收到阅后即焚消息开始倒计时
41
+ */
42
+ readonly MESSAGE_OPEN_CLOCK: "messageOpenClock";
39
43
  /**
40
44
  * sdk收到直播间message
41
45
  */
@@ -78,6 +82,16 @@ export type CHAT_SDK_EVENT_MAP = {
78
82
  */
79
83
  message_ids: string[];
80
84
  };
85
+ [CHAT_SDK_EVENT.MESSAGE_OPEN_CLOCK]: {
86
+ /**
87
+ * 收到的消息所属的feed_id
88
+ */
89
+ feed_id: string;
90
+ /**
91
+ * 收到的消息
92
+ */
93
+ message_ids: string[];
94
+ };
81
95
  [CHAT_SDK_EVENT.MESSAGE_RECALLED]: {
82
96
  /**
83
97
  * 撤回的消息id列表
@@ -24,6 +24,18 @@ export type PushMessageAddMessage = PushMessageBase<PushMessageType.ADD_MESSAGE,
24
24
  no_last_msg?: Bool;
25
25
  }>;
26
26
  export type PushMessageUpdateMessage = PushMessageBase<PushMessageType.UPDATE_MESSAGE, Partial<Message> & Pick<Message, 'id' | 'chat_id' | 'thread_id'>>;
27
+ export type PushMessageDeleteMessage = PushMessageBase<PushMessageType.DELETE_MESSAGE, Partial<Message> & Pick<Message, 'id' | 'chat_id' | 'thread_id'> & {
28
+ expire_ids?: string[];
29
+ }>;
30
+ export type PushMessageOpenClockMessage = PushMessageBase<PushMessageType.MSG_OPEN_CLOCK, {
31
+ msgs_open_clock: Array<{
32
+ message_id: string;
33
+ open_clock: number;
34
+ msg_expire_at: number;
35
+ }>;
36
+ chat_id: string;
37
+ thread_id: string;
38
+ }>;
27
39
  export type PushMessageDeleteFeed = PushMessageBase<PushMessageType.DELETE_FEED, {
28
40
  /**
29
41
  * feed id
@@ -76,5 +88,5 @@ export type PushMessageUpdateUserData = PushMessageBase<PushMessageType.UPDATE_U
76
88
  avatar?: string;
77
89
  }>;
78
90
  export type PushMessageUpdateFeedData = PushMessageBase<PushMessageType.UPDATE_FEED, Feed>;
79
- export type SpecialPushMessage = PushMessagePong | PushMessageBigPackage | PushMessageCreateFeed | PushMessageUpdateFeeds | PushMessageAddMessage | PushMessageUpdateMessage | PushMessageDeleteFeed | PushMessagePushLiveMessage | PushMessageReadMessage | PushMessagePushSystemNotice | PushMessageAddGroupMember | PushMessageDelGroupMember | PushMessageUpdateGroup | PushMessageUpdateUserData | PushMessageUpdateMessageReaction | PushMessageUpdateFeedData;
91
+ export type SpecialPushMessage = PushMessagePong | PushMessageBigPackage | PushMessageCreateFeed | PushMessageUpdateFeeds | PushMessageAddMessage | PushMessageUpdateMessage | PushMessageDeleteFeed | PushMessagePushLiveMessage | PushMessageReadMessage | PushMessagePushSystemNotice | PushMessageAddGroupMember | PushMessageDelGroupMember | PushMessageUpdateGroup | PushMessageUpdateUserData | PushMessageUpdateMessageReaction | PushMessageUpdateFeedData | PushMessageDeleteMessage | PushMessageOpenClockMessage;
80
92
  export type PushMessage = PushMessageBase<Exclude<PushMessageType, SpecialPushMessage['type']>> | SpecialPushMessage;
@@ -7,6 +7,8 @@ export default class ChatSDK extends Base<CHAT_SDK_EVENT_MAP> {
7
7
  private context;
8
8
  private version;
9
9
  private singletonLock;
10
+ private tabSessionCoordinator;
11
+ private restoreLoginPromise;
10
12
  private logger;
11
13
  private httpClient;
12
14
  private feedCache;
@@ -14,6 +16,9 @@ export default class ChatSDK extends Base<CHAT_SDK_EVENT_MAP> {
14
16
  private pushMessageProcessor;
15
17
  constructor(config: ChatSDKConfig);
16
18
  private init;
19
+ private getTransferableLoginSession;
20
+ private restoreLoginFromActiveTab;
21
+ private doRestoreLoginFromActiveTab;
17
22
  private requestDeviceId;
18
23
  private saveContext;
19
24
  private loadContext;
@@ -42,6 +47,7 @@ export default class ChatSDK extends Base<CHAT_SDK_EVENT_MAP> {
42
47
  */
43
48
  logout(): Promise<HttpClientResponse>;
44
49
  private afterLogout;
50
+ private deactivateByTakeover;
45
51
  /**
46
52
  * 获取当前登录用户的user_id
47
53
  * @returns
@@ -76,6 +82,17 @@ export default class ChatSDK extends Base<CHAT_SDK_EVENT_MAP> {
76
82
  * @returns
77
83
  */
78
84
  getFeedMemberList(feed_id: string): Promise<HttpClientResponse<Chatter[]>>;
85
+ /**
86
+ * 根据 user_ids 或 uids 批量获取用户信息
87
+ * @param params
88
+ * @returns
89
+ */
90
+ getUserByUids(params: {
91
+ user_ids?: string[];
92
+ uids?: string[];
93
+ }): Promise<HttpClientResponse<Array<{
94
+ id: string;
95
+ }>>>;
79
96
  private getDomain;
80
97
  /**
81
98
  * 检测链接域名并为需要鉴权的域名添加x-sid参数
@@ -139,6 +156,11 @@ export default class ChatSDK extends Base<CHAT_SDK_EVENT_MAP> {
139
156
  * @returns {Promise<HttpClientResponse>} 请求结果
140
157
  */
141
158
  leaveRoom(room_id: string): Promise<HttpClientResponse>;
159
+ /**
160
+ * 获取已加入的直播间
161
+ * @returns {Promise<HttpClientResponse>} 请求结果
162
+ */
163
+ getJoinedRooms(): Promise<HttpClientResponse>;
142
164
  /**
143
165
  * 获取直播间的最近50条消息
144
166
  * @param room_id 直播间id
@@ -22,6 +22,8 @@ export default class PushMessageProcessor {
22
22
  private processDeleteFeed;
23
23
  private processAddMessage;
24
24
  private processUpdateMessage;
25
+ private processDeleteMessage;
26
+ private processOpenClockMessage;
25
27
  private processPushLiveMessage;
26
28
  private processPushSystemNotice;
27
29
  private processReadMessage;
@@ -3,6 +3,7 @@ import Base from './Base';
3
3
  import Logger from './Logger';
4
4
  export type ReConnectWebsocketConfig = {
5
5
  url: string;
6
+ token: string;
6
7
  logger: Logger;
7
8
  };
8
9
  export default class ReConnectWebsocket extends Base<{
@@ -10,6 +11,7 @@ export default class ReConnectWebsocket extends Base<{
10
11
  kickoff: void;
11
12
  }> {
12
13
  private url;
14
+ private token;
13
15
  private logger;
14
16
  private ws;
15
17
  private destroyed;
@@ -1,7 +1,12 @@
1
+ export type SingletonLockRequestOptions = {
2
+ timeoutMs?: number;
3
+ retryIntervalMs?: number;
4
+ };
1
5
  export default class SingletonLock {
2
6
  private obtained;
3
7
  private abortLockObtain;
4
8
  constructor();
5
- requestLock(): Promise<boolean>;
9
+ requestLock(options?: SingletonLockRequestOptions): Promise<boolean>;
10
+ private requestLockOnce;
6
11
  releaseLock(): void;
7
12
  }
@@ -0,0 +1,33 @@
1
+ import Logger from './Logger';
2
+ export type TransferableLoginSession = {
3
+ deviceId: string | null;
4
+ loginUser: {
5
+ userId: string;
6
+ secretKey: string;
7
+ sessionId: string;
8
+ };
9
+ };
10
+ export type TabSessionCoordinatorConfig = {
11
+ onTakeoverRequest: () => void | Promise<void>;
12
+ getCurrentSession?: () => TransferableLoginSession | null;
13
+ logger?: Logger;
14
+ };
15
+ export default class TabSessionCoordinator {
16
+ private tabId;
17
+ private channel;
18
+ private closed;
19
+ private handledTakeoverIds;
20
+ private handledSessionRequestIds;
21
+ private pendingSessionRequests;
22
+ private onTakeoverRequest;
23
+ private getCurrentSession;
24
+ private logger;
25
+ constructor(config: TabSessionCoordinatorConfig);
26
+ requestTakeover(): void;
27
+ requestCurrentSession(timeoutMs?: number): Promise<TransferableLoginSession | null>;
28
+ destroy(): void;
29
+ private publish;
30
+ private handleBroadcastMessage;
31
+ private handleStorageMessage;
32
+ private handleMessage;
33
+ }
@@ -0,0 +1,3 @@
1
+ export declare const WEBSOCKET_AUTH_PROTOCOL = "typex.im.auth.v1";
2
+ export declare function encodeTokenForWebSocketProtocol(token: string): string;
3
+ export declare function buildWebSocketAuthProtocols(token: string): string[];
@@ -1 +1 @@
1
- import e from"axios";import t from"crypto-js";var i,s,n,r,o,a,c,d;!function(e){e[e.yes=1]="yes",e[e.no=0]="no"}(i||(i={})),function(e){e[e.CREATE_FEED=0]="CREATE_FEED",e[e.UPDATE_FEED=1]="UPDATE_FEED",e[e.ADD_MESSAGE=2]="ADD_MESSAGE",e[e.UPDATE_MESSAGE=3]="UPDATE_MESSAGE",e[e.UPDATE_USER_DATA=4]="UPDATE_USER_DATA",e[e.USER_LOGIN=5]="USER_LOGIN",e[e.READ_MESSAGE=6]="READ_MESSAGE",e[e.PONG_MESSAGE=8]="PONG_MESSAGE",e[e.DELETE_MESSAGE=9]="DELETE_MESSAGE",e[e.UPDATE_GROUP=12]="UPDATE_GROUP",e[e.DELETE_GROUP=13]="DELETE_GROUP",e[e.UPDATE_LOGIN_USER=17]="UPDATE_LOGIN_USER",e[e.UPDATE_MESSAGE_REACTION=19]="UPDATE_MESSAGE_REACTION",e[e.ADD_GROUP_MEMBER=21]="ADD_GROUP_MEMBER",e[e.DEL_GROUP_MEMBER=22]="DEL_GROUP_MEMBER",e[e.ADD_CONTACTS=23]="ADD_CONTACTS",e[e.UPDATE_CONTACTS=24]="UPDATE_CONTACTS",e[e.DEL_CONTACTS=25]="DEL_CONTACTS",e[e.BLOCK_USER=26]="BLOCK_USER",e[e.DEVICE_CODE=27]="DEVICE_CODE",e[e.MSG_OPEN_CLOCK=28]="MSG_OPEN_CLOCK",e[e.DELETE_SECRET_CHAT=29]="DELETE_SECRET_CHAT",e[e.DELETE_FEED=30]="DELETE_FEED",e[e.FAVORITE_UPDATE=31]="FAVORITE_UPDATE",e[e.STICKERS_UPDATE=32]="STICKERS_UPDATE",e[e.CUSTOM_STICKERS_UPDATE=33]="CUSTOM_STICKERS_UPDATE",e[e.MANAGE_DEVICE_UPDATE=34]="MANAGE_DEVICE_UPDATE",e[e.MASS_MESSAGE_UPDATE=35]="MASS_MESSAGE_UPDATE",e[e.CHAT_WALLPAPER_DELETE=36]="CHAT_WALLPAPER_DELETE",e[e.CHAT_WALLPAPER_ADD=37]="CHAT_WALLPAPER_ADD",e[e.CONTACT_REQUEST=40]="CONTACT_REQUEST",e[e.USER_PREFERENCE_CHANGE=38]="USER_PREFERENCE_CHANGE",e[e.UPDATE_GROUP_PIN=41]="UPDATE_GROUP_PIN",e[e.RTC_CANCEL=46]="RTC_CANCEL",e[e.ADD_FEED_FOLDER=43]="ADD_FEED_FOLDER",e[e.UPDATE_FEED_FOLDER=44]="UPDATE_FEED_FOLDER",e[e.UPDATE_FOLDER_FEED_LIST=47]="UPDATE_FOLDER_FEED_LIST",e[e.DELETE_FEED_FOLDER=45]="DELETE_FEED_FOLDER",e[e.UPDATE_CHATTER=42]="UPDATE_CHATTER",e[e.PAPER_KEY=48]="PAPER_KEY",e[e.PAPER_KEY_LOG=49]="PAPER_KEY_LOG",e[e.USER_LOGIN_SCAN=50]="USER_LOGIN_SCAN",e[e.RTC_RINGING=51]="RTC_RINGING",e[e.ON_UPDATE_PRIVATE_SETTING=52]="ON_UPDATE_PRIVATE_SETTING",e[e.ON_DELETE_PRIVATE_SETTING=53]="ON_DELETE_PRIVATE_SETTING",e[e.ON_UPDATE_LOGIN_PRIVATE_SETTING=54]="ON_UPDATE_LOGIN_PRIVATE_SETTING",e[e.PUSH_LIVE_MESSAGE=56]="PUSH_LIVE_MESSAGE",e[e.PUSH_SYSTEM_NOTICE=58]="PUSH_SYSTEM_NOTICE",e[e.BIG_PACKAGE_PUSH=126]="BIG_PACKAGE_PUSH",e[e.KICK_OUT_DEVICE=127]="KICK_OUT_DEVICE",e[e.CLEAR_HISTORY=128]="CLEAR_HISTORY",e[e.CLEAR_DATA=255]="CLEAR_DATA"}(s||(s={})),function(e){e[e.singleChat=1]="singleChat",e[e.groupChat=2]="groupChat"}(n||(n={})),function(e){e[e.normal=0]="normal",e[e.thread=1]="thread"}(r||(r={})),function(e){e[e.text=0]="text",e[e.system=1]="system"}(o||(o={})),function(e){e[e.text=0]="text",e[e.image=1]="image",e[e.card=2]="card",e[e.audio=3]="audio",e[e.video=4]="video",e[e.file=5]="file",e[e.mergeForward=6]="mergeForward",e[e.sticker=7]="sticker",e[e.richText=8]="richText",e[e.custom=9]="custom"}(a||(a={})),function(e){e[e.Owner=1]="Owner",e[e.Admin=2]="Admin",e[e.Common=3]="Common",e[e.Bot=4]="Bot"}(c||(c={})),function(e){e[e.normal=0]="normal",e[e.recall=1]="recall",e[e.destroy=2]="destroy",e[e.edit=3]="edit",e[e.main_delete=4]="main_delete"}(d||(d={}));const l=["api-coco.typex.im","api-tx.typex-test.cn"];var h,_,u;!function(e){e.error="ERROR",e.warning="WARNING",e.info="INFO"}(h||(h={})),function(e){e[e.SDK_ERROR=-1e4]="SDK_ERROR",e[e.NETWORK_ERROR=-9999]="NETWORK_ERROR",e[e.MAKE_SIGN_FAIL=-9998]="MAKE_SIGN_FAIL",e[e.REQUEST_SINGLETON_LOCK_FAIL=-9997]="REQUEST_SINGLETON_LOCK_FAIL",e[e.SUCCESS=0]="SUCCESS"}(_||(_={})),function(e){e[e.up=0]="up",e[e.down=1]="down"}(u||(u={}));var g=Object.freeze({__proto__:null,get Bool(){return i},get ChatType(){return n},get FeedType(){return r},get GroupRole(){return c},get HttpClientResponseCode(){return _},get LogLevel(){return h},get MessageKind(){return o},get MessageOperation(){return d},get MessageType(){return a},get PushMessageType(){return s},RESOURCE_AUTH_DOMAINS:l,get RequestDirection(){return u}});const E={SDK_READY:"sdkReady",SDK_NOT_READY:"sdkNotReady",FEED_LIST_UPDATED:"feedListUpdated",MESSAGE_RECEIVED:"messageReceived",MESSAGE_RECALLED:"messageRecalled",MESSAGE_EDITED:"messageEdited",MESSAGE_DESTROYED:"messageDestroyed",MESSAGE_REACTION_UPDATED:"messageReactionUpdated",MESSAGE_RECEIPT_RECEIVED:"messageReceiptReceived",ROOM_MESSAGE_RECEIVED:"roomMessageReceived",SYSTEM_NOTICE_RECEIVED:"systemNoticeReceived"};var p=Object.freeze({__proto__:null,CHAT_SDK_EVENT:E}),m=Object.freeze({__proto__:null});function f(e,t){return{ok:!1,code:e,msg:t}}function b(e){return{ok:!0,data:e}}const S=e=>{try{return null==e||"string"!=typeof e||0===e.length?null:JSON.parse(e)}catch{return null}},C=e=>{const t=S(e);if(null!==t){let e;return null!=t.content&&(e=S(t.content)??void 0),{client_msg_id:t.client_msg_id,content:e}}return{}},T=e=>e.replace(/[.*+?^${}()|[\]\\]/g,"\\$&"),A=e=>new RegExp(`https?:\\\\?/\\\\?/${T(e)}(?:\\\\.|[^"\\\\\\s])*`,"g"),y=(e,t,i)=>{if(!e||"string"!=typeof e)return e;const s=A(t);return e.replace(s,e=>{const t=(e=>{try{return JSON.parse(`"${e}"`)}catch{return e}})(e),s=i(t);return"string"!=typeof s||s===t?e:(n=s,JSON.stringify(n).slice(1,-1));var n})};class R{constructor(e){Object.defineProperty(this,"all",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),this.all=e||new Map}on(e,t){const i=this.all.get(e);return i?i.push(t):this.all.set(e,[t]),()=>{this.off(e,t)}}off(e,t){const i=this.all.get(e);i&&(t?i.splice(i.indexOf(t)>>>0,1):this.all.set(e,[]))}emit(e,t){let i=this.all.get(e);i&&i.slice().map(e=>{e(t)}),i=this.all.get("*"),i&&i.slice().map(i=>{i(e,t)})}once(e,t){if("*"===e){const i=(e,s)=>{t(e,s),this.off("*",i)};this.on(e,i)}else{const i=s=>{t(s),this.off(e,i)};this.on(e,i)}}}class D extends R{constructor(e){super(),Object.defineProperty(this,"url",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"logger",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"ws",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"destroyed",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"pingTimeout",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"pongTimeout",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"reConnectTimeout",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),this.url=e.url,this.logger=e.logger,this.ws=null,this.destroyed=!1,this.pingTimeout=null,this.pongTimeout=null,this.reConnectTimeout=null,this.reConnect=this.reConnect.bind(this),window.addEventListener("online",this.reConnect),this.connect()}disconnect(){this.ws&&(this.ws.onopen=null,this.ws.onerror=null,this.ws.onmessage=null,this.ws.onclose=null,this.ws.close(),this.ws=null),null!==this.pingTimeout&&(clearTimeout(this.pingTimeout),this.pingTimeout=null),null!==this.pongTimeout&&(clearTimeout(this.pongTimeout),this.pongTimeout=null),null!==this.reConnectTimeout&&(clearTimeout(this.reConnectTimeout),this.reConnectTimeout=null)}connect(){if(this.ws)return void this.logger.warn("ReConnectWebsocket try connect but already connected");const e=new WebSocket(this.url);this.ws=e,e.onopen=()=>{this.delaySendPing()},e.onerror=e=>{this.logger.info("ReConnectWebsocket error",e)},e.onmessage=e=>{try{const t=JSON.parse(e.data);if(t.type===s.PONG_MESSAGE?null!==this.pongTimeout&&(clearTimeout(this.pongTimeout),this.pongTimeout=null,this.delaySendPing()):this.sendAck(t.id),t.type===s.BIG_PACKAGE_PUSH)for(const e of t.content.big_push)this.emit("message",e);else this.emit("message",t)}catch(e){this.logger.error("ReConnectWebsocket message parse failed",e)}},e.onclose=e=>{4001===e.code?this.kickOff():this.reConnect()}}reConnect(){this.disconnect(),this.destroyed||(this.reConnectTimeout=setTimeout(()=>{this.reConnectTimeout=null,this.connect()},5e3))}send(e){if(this.destroyed)return!1;if(!this.ws)return this.logger.warn("ReConnectWebsocket send before connect"),!1;try{return this.ws.readyState!==this.ws.OPEN?(this.logger.warn("ReConnectWebsocket send but not open",this.ws.readyState),!1):(this.ws.send(JSON.stringify(e)),!0)}catch(e){return this.logger.warn("ReConnectWebsocket send error",e),!1}}sendAck(e){this.send({type:1,ids:[e]})}destroy(){this.destroyed||(this.destroyed=!0,this.disconnect(),window.removeEventListener("online",this.reConnect))}delaySendPing(){null!==this.pingTimeout&&(clearTimeout(this.pingTimeout),this.pingTimeout=null),this.pingTimeout=setTimeout(()=>{this.pingTimeout=null;this.send({type:0})?this.waitPong():this.reConnect()},2e4)}waitPong(){this.pongTimeout=setTimeout(()=>{this.logger.info("ReConnectWebsocket pong timeout"),this.reConnect()},1e4)}kickOff(){this.destroy(),this.emit("kickoff")}}class v extends R{constructor(e){super(),Object.defineProperty(this,"host",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"context",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"logger",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"ws",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),this.host=e.host,this.context=e.context,this.logger=e.logger,this.ws=null}connect(){if(null===this.context.loginUser)return void this.logger.warn("BusinessWebsocket try connect but not login");if(this.ws)return void this.logger.warn("BusinessWebsocket try connect but already connected");const e=`${this.host}/ws?token=${this.context.loginUser.sessionId}&platform=web`;this.ws=new D({url:e,logger:this.logger}),this.ws.on("message",e=>{this.emit("message",e)}),this.ws.on("kickoff",()=>{this.emit("kickoff")})}disconnect(){this.ws?(this.ws.destroy(),this.ws=null):this.logger.info("BusinessWebsocket already disconnected")}}class w{constructor(){Object.defineProperty(this,"syncCompleted",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"map",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"chatMap",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"threadMap",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"targetMap",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"list",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"waitMap",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),this.syncCompleted=!1,this.map=new Map,this.chatMap=new Map,this.threadMap=new Map,this.targetMap=new Map,this.waitMap=new Map,this.list=[]}getAll(){const e=[];for(const t of this.list){const i=this.map.get(t);i&&e.push(i)}return e}get(e){return this.map.get(e)??null}getByChat(e,t){let i;return i=t&&"0"!==t?this.threadMap.get(t):this.chatMap.get(e),void 0!==i?this.get(i):null}getByTargetId(e){const t=this.targetMap.get(e);if(void 0===t)return[];const i=[];for(const e of t){const t=this.get(e);null!==t&&i.push(t)}return i}async waitFor(e){const t=this.get(e);if(t)return t;if(this.syncCompleted)return null;let i=this.waitMap.get(e);return i||(i=(()=>{let e=()=>{};return{promise:new Promise(t=>{e=t}),resolve:e}})(),this.waitMap.set(e,i)),await i.promise,this.get(e)}resolveWait(e){const t=this.waitMap.get(e);t&&(t.resolve(),this.waitMap.delete(e))}removeFromList(e){const t=this.list.indexOf(e);t>-1&&this.list.splice(t,1)}remove(e){const t=this.map.get(e);if(t){if(this.map.delete(e),t.feed_type===r.thread)this.threadMap.delete(t.thread_id);else if(this.chatMap.delete(t.chat_id),t.target_id&&"0"!==t.target_id){const e=this.targetMap.get(t.target_id);void 0!==e&&(e.delete(t.id),0===e.size&&this.targetMap.delete(t.target_id))}return this.removeFromList(e),!0}return!1}beforeSave(e){if(this.map.has(e.id))this.removeFromList(e.id);else if(e.feed_type===r.thread)this.threadMap.set(e.thread_id,e.id);else if(this.chatMap.set(e.chat_id,e.id),e.target_id&&"0"!==e.target_id){if(!this.targetMap.has(e.target_id)){const t=new Set;this.targetMap.set(e.target_id,t)}this.targetMap.get(e.target_id)?.add(e.id)}this.map.set(e.id,e)}afterSave(e){this.resolveWait(e.id)}push(e){this.beforeSave(e),this.list.push(e.id),this.afterSave(e)}unshift(e){this.beforeSave(e),this.list.unshift(e.id),this.afterSave(e)}update(e){this.map.has(e.id)&&this.map.set(e.id,e)}markSyncComplete(){this.syncCompleted=!0;for(const[e,t]of this.waitMap)t.resolve();this.waitMap.clear()}isSyncCompleted(){return this.syncCompleted}reset(){this.syncCompleted=!1,this.map.clear(),this.chatMap.clear(),this.threadMap.clear(),this.targetMap.clear(),this.waitMap.clear(),this.list=[]}}function P(e){return(new TextEncoder).encode(e).buffer}async function O(e,i){return window.crypto&&window.crypto.subtle?await async function(e,t){const i=P(t),s=P(e),n=await crypto.subtle.importKey("raw",i,{name:"HMAC",hash:{name:"SHA-256"}},!1,["sign"]),r=await crypto.subtle.sign("HMAC",n,s);return Array.from(new Uint8Array(r)).map(e=>e.toString(16).padStart(2,"0")).join("")}(e,i):function(e,i){return t.HmacSHA256(e,i).toString(t.enc.Hex)}(e,i)}const M=e=>{if(null==e)return"";if("object"!=typeof e||Array.isArray(e)){if(Array.isArray(e)){let t="";for(const i of e)t+=M(i);return t}return"string"==typeof e?e:String(e)}{const t=Object.keys(e).sort();let i="";for(const s of t)i+=M(e[s]);return i}};function L(){return f(_.MAKE_SIGN_FAIL,"make sign fail")}class U{constructor(t){Object.defineProperty(this,"api",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"context",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"logger",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),this.api=e.create({baseURL:t.host,headers:{"x-developer":t.developer},withCredentials:!0}),this.context=t.context,this.logger=t.logger}async request(e){try{const{needSign:t=!0,...i}=e;if(i.headers||(i.headers={}),i.headers.platform="web",t&&"POST"===e.method?.toUpperCase()&&i.data){if(null===this.context.loginUser)return this.logger.warn("HttpClient needs make sign but not login"),L();try{const e=await(async(e,t)=>{const i=await M(e);return await O(i,t)})(i.data,this.context.loginUser.secretKey);i.headers.sign=e}catch(e){return this.logger.error("HttpClient make sign error",e),L()}}this.context.loginUser&&(i.headers["X-Sid"]=this.context.loginUser.sessionId);const s=await this.api(i),n=s.data;return n.code===_.SUCCESS?{ok:!0,data:n.data}:(this.logger.info("HttpClient server error",s),{ok:!1,code:n.code,msg:n.msg,msg_i18n:n.msg_i18n})}catch{return{ok:!1,code:_.NETWORK_ERROR,msg:"network error"}}}get(e,t,i){return this.request({url:e,method:"GET",params:t,...i})}post(e,t,i){return this.request({url:e,method:"POST",data:t,...i})}}function I(e){return`${e}`.padStart(2,"0")}class k{constructor(){Object.defineProperty(this,"level",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"logHandler",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),this.level=h.error,this.logHandler=this.createLogHandler()}getPriority(e){switch(e){case h.error:return 3;case h.warning:return 2;case h.info:return 1;default:return 0}}createLogHandler(){return(e,...t)=>{const i=new Date,s=`TypeX >> [${`${i.getFullYear()}-${I(i.getMonth()+1)}-${I(i.getDate())} ${I(i.getHours())}:${I(i.getMinutes())}:${I(i.getSeconds())}.${i.getMilliseconds()}`}]`;switch(e){case h.error:console.error(s,"[ERR]",...t);break;case h.warning:console.warn(s,"[WARN]",...t);break;case h.info:console.info(s,"[INFO]",...t);break;default:console.log(s,...t)}}}log(e,...t){this.getPriority(e)>=this.getPriority(this.level)&&this.logHandler(e,...t)}setLogLevel(e){this.level=e,this.logHandler=this.createLogHandler()}info(...e){this.log(h.info,...e)}warn(...e){this.log(h.warning,...e)}error(...e){this.log(h.error,...e)}}class G{constructor(e){Object.defineProperty(this,"context",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"logger",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"emitter",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"feedCache",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"handleKickoff",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),this.context=e.context,this.logger=e.logger,this.emitter=e.emitter,this.feedCache=e.feedCache,this.handleKickoff=e.onKickoff}emitFeedListUpdated(){this.emitter.emit(E.FEED_LIST_UPDATED,{list:this.feedCache.getAll(),is_sync_completed:this.feedCache.isSyncCompleted()})}processCreateFeed(e){this.feedCache.unshift(e.content),this.emitFeedListUpdated()}processUpdateFeed(e){const t=e.content,i=this.feedCache.getByChat(t.chat_id,t.thread_id);if(null===i)return;const s={...i,...t};this.feedCache.update(s),this.emitFeedListUpdated()}processDeleteFeed(e){this.feedCache.remove(e.content.id)&&this.emitFeedListUpdated()}processAddMessage(e){if(null===this.context.loginUser)return;const t=this.context.loginUser.userId,s=e.content;if(s.hide_ids.includes(t))return;const n=this.feedCache.getByChat(s.chat_id,s.thread_id);if(null!==n){if(s.no_last_msg!==i.yes){let e=!1,r=!1;const a={};if(s.message_kind_id!==o.system&&s.sender_id!==t&&s.no_read!==i.yes){e=!0;const t=new Set(n.unread_message_ids);t.add(s.id),a.unread_message_ids=[...t],a.badge=t.size}if(n.last_message_position<s.position&&(e=!0,r=!0,a.last_message_id=s.id,a.last_message_position=s.position,a.last_message_sender_id=s.sender_id,a.last_message_send_at=s.send_at,a.last_message_kind_id=s.message_kind_id,a.last_message_type_id=s.message_type_id,a.last_message=s.content,a.last_message_operation=s.operation,a.last_message_operation_user_id=s.operation_user_id),e){const e={...n,...a};r?this.feedCache.unshift(e):this.feedCache.update(e),this.emitFeedListUpdated()}}this.emitter.emit(E.MESSAGE_RECEIVED,{feed_id:n.id,message:s})}}processUpdateMessage(e){const t=e.content,i=this.feedCache.getByChat(t.chat_id,t.thread_id);if(null!==i&&null!=t.operation){let e=!1;const s={};if(t.operation===d.recall||t.operation===d.destroy){if(null!=i.unread_message_ids&&i.unread_message_ids.includes(t.id)){e=!0;const n=new Set(i.unread_message_ids);n.delete(t.id),s.unread_message_ids=[...n],s.badge=s.unread_message_ids.length}i.last_message_id===t.id&&(e=!0,s.last_message=t.content??"{}",s.last_message_operation=t.operation,s.last_message_operation_user_id=t.operation_user_id??"0")}else t.operation===d.edit&&i.last_message_id===t.id&&(e=!0,s.last_message_kind_id=t.message_kind_id,s.last_message_type_id=t.message_type_id,s.last_message=t.content,s.last_message_operation=t.operation,s.last_message_operation_user_id=t.operation_user_id);e&&(this.feedCache.update({...i,...s}),this.emitFeedListUpdated()),t.operation===d.recall?this.emitter.emit(E.MESSAGE_RECALLED,{message_ids:[t.id]}):t.operation===d.edit?null!=t.content&&null!=t.edited_at&&null!=t.message_kind_id&&null!=t.message_type_id&&null!=t.operation_user_id&&this.emitter.emit(E.MESSAGE_EDITED,{chat_id:t.chat_id,content:t.content,edited_at:t.edited_at,id:t.id,message_kind_id:t.message_kind_id,message_type_id:t.message_type_id,operation:t.operation,operation_user_id:t.operation_user_id,thread_id:t.thread_id}):t.operation===d.destroy&&this.emitter.emit(E.MESSAGE_DESTROYED,{feed_id:i.id,message_ids:[t.id]})}}processPushLiveMessage(e){this.emitter.emit(E.ROOM_MESSAGE_RECEIVED,{room_id:e.content.room_id,content:e.content.message})}processPushSystemNotice(e){this.emitter.emit(E.SYSTEM_NOTICE_RECEIVED,{content:e.content})}processReadMessage(e){if(null===this.context.loginUser)return;const t=this.context.loginUser.userId,i=e.content,s=this.feedCache.getByChat(i.chat_id,i.thread_id);if(null===s)return;let n=!1;const r={};if(i.reader_ids.includes(t)&&i.message_ids.length>0){n=!0;const e=new Set(s.unread_message_ids);i.message_ids.forEach(t=>{e.delete(t)}),r.unread_message_ids=[...e],r.badge=e.size}n&&(this.feedCache.update({...s,...r}),this.emitFeedListUpdated()),this.emitter.emit(E.MESSAGE_RECEIPT_RECEIVED,{feed_id:s.id,message_ids:i.message_ids,reader_user_ids:i.reader_ids})}processKickOutDevice(){this.handleKickoff()}processGroupMember(e){const t=e.content,i=this.feedCache.getByChat(t.chat_id,"0");if(null===i)return;const n=new Set(i.chat_member),r=e.type===s.ADD_GROUP_MEMBER,o=e.type===s.DEL_GROUP_MEMBER;t.chat_member.forEach(e=>{r?n.add(e.chat_id):o&&n.delete(e.chat_id)}),this.feedCache.update({...i,chat_member:[...n]}),this.emitFeedListUpdated()}processUpdateGroup(e){const t=e.content,i=this.feedCache.getByChat(t.chat_id,"0");if(null===i)return;let s=!1;const n={};null!=t.avatar&&(s=!0,n.avatar=t.avatar),null!=t.name&&(s=!0,n.name=t.name),s&&(this.feedCache.update({...i,...n}),this.emitFeedListUpdated())}processUpdateUserData(e){const t=e.content,i=this.feedCache.getByTargetId(t.id);if(i.length>0){const e={};if(null!=t.avatar&&(e.avatar=t.avatar),null!=t.first_name||null!=t.last_name){let i=t.first_name??"";null!=t.last_name&&(i=i.length>0?`${i} ${t.last_name}`:t.last_name),e.name=i}for(const t of i)this.feedCache.update({...t,...e});this.emitFeedListUpdated()}}processUpdateMessageReaction(e){const t=e.content,i=this.feedCache.getByChat(t.chat_id,t.thread_id);null!==i&&this.emitter.emit(E.MESSAGE_REACTION_UPDATED,{feed_id:i.id,message_id:t.message_id,reactions:t.reactions})}process(e){switch(this.logger.info("PushMessageProcessor process",e),e.type){case s.CREATE_FEED:this.processCreateFeed(e);break;case s.UPDATE_FEED:this.processUpdateFeed(e);break;case s.DELETE_FEED:this.processDeleteFeed(e);break;case s.ADD_MESSAGE:this.processAddMessage(e);break;case s.UPDATE_MESSAGE:this.processUpdateMessage(e);break;case s.PUSH_LIVE_MESSAGE:this.processPushLiveMessage(e);break;case s.PUSH_SYSTEM_NOTICE:this.processPushSystemNotice(e);break;case s.READ_MESSAGE:this.processReadMessage(e);break;case s.KICK_OUT_DEVICE:this.processKickOutDevice();break;case s.ADD_GROUP_MEMBER:case s.DEL_GROUP_MEMBER:this.processGroupMember(e);break;case s.UPDATE_GROUP:this.processUpdateGroup(e);break;case s.UPDATE_USER_DATA:this.processUpdateUserData(e);break;case s.UPDATE_MESSAGE_REACTION:this.processUpdateMessageReaction(e)}}}class x{constructor(){Object.defineProperty(this,"obtained",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"abortLockObtain",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),this.obtained=!1,this.abortLockObtain=null}async requestLock(){if(this.obtained)return!0;let e=()=>{};const t=new Promise(t=>{e=t}),i=new Promise(e=>{this.abortLockObtain=e});navigator.locks.request("typex-sdk",{ifAvailable:!0},async t=>{t?(this.obtained=!0,e(!0),await i):e(!1)});return await t}releaseLock(){this.obtained=!1,null!==this.abortLockObtain&&(this.abortLockObtain(),this.abortLockObtain=null)}}class N{static set(e){localStorage.setItem(this.key,JSON.stringify(e))}static get(){try{const e=localStorage.getItem(this.key);if(!e)return null;return JSON.parse(e)}catch{return null}}static clear(){localStorage.removeItem(this.key)}}Object.defineProperty(N,"key",{enumerable:!0,configurable:!0,writable:!0,value:"__typex_sdk_data__"});class F{constructor(){Object.defineProperty(this,"version",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),this.version=0}increment(){this.version++}get(){return this.version}check(e){return e===this.version}}class K extends R{constructor(e){super(),Object.defineProperty(this,"context",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"version",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"singletonLock",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"logger",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"httpClient",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"feedCache",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"ws",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"pushMessageProcessor",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),this.context={isLogin:!1,loginUser:null,isReady:!1,deviceId:null},this.version=new F,this.singletonLock=new x,this.logger=new k,this.httpClient=new U({host:e.httpHost,context:this.context,logger:this.logger,developer:e.developer}),this.feedCache=new w,this.ws=new v({host:e.websocketHost,context:this.context,logger:this.logger}),this.pushMessageProcessor=new G({context:this.context,logger:this.logger,emitter:this,feedCache:this.feedCache,onKickoff:()=>{this.afterLogout()}}),this.init()}init(){this.loadContext(),this.ws.on("message",e=>{this.pushMessageProcessor.process(e)}),this.ws.on("kickoff",()=>{this.afterLogout()})}async requestDeviceId(){if(this.context.deviceId)return!0;const e=await this.httpClient.post("/device_api/device_id",{platform:"web",hash_str:""},{needSign:!1});return!!e.ok&&(this.context.deviceId=e.data,this.saveContext(),!0)}saveContext(){const{context:e}=this;N.set({deviceId:e.deviceId})}loadContext(){const e=N.get();e&&e.deviceId&&(this.context.deviceId=e.deviceId)}applyLoginStatus(){this.version.increment(),this.saveContext(),this.context.isLogin?(this.ws.connect(),this.loadFeedList(),this.context.isReady=!0,this.emit(E.SDK_READY)):(this.ws.disconnect(),this.feedCache.reset(),this.singletonLock.releaseLock(),this.context.isReady=!1,this.emit(E.SDK_NOT_READY))}async loadFeedList(){const e=this.version.get(),t={refresh_at:null,feed_id:null};for(;;){const i=await this.httpClient.get("/feed",{limit:500,last_refresh_at:t.refresh_at??void 0,last_feed_id:t.feed_id??void 0});if(!this.version.check(e))break;if(!i.ok||null===i.data)break;if(t.refresh_at=i.data.refresh_at,t.feed_id=i.data.last_feed_id,(i.data.feed_list??[]).forEach(e=>{this.feedCache.push(e)}),!i.data.has_more)break}this.version.check(e)&&(this.feedCache.markSyncComplete(),this.emit(E.FEED_LIST_UPDATED,{list:this.feedCache.getAll(),is_sync_completed:!0}))}isReady(){return this.context.isReady}setLogLevel(e){this.logger.setLogLevel(e)}async login(e){if(this.context.isLogin)return b(null);if(!await this.singletonLock.requestLock())return this.logger.error("Another active TypeX SDK instance detected"),f(_.REQUEST_SINGLETON_LOCK_FAIL,"Another active TypeX SDK instance detected");if(await this.requestDeviceId(),!this.context.deviceId)return this.logger.error("Get deviceId failed"),f(_.SDK_ERROR,"Get deviceId failed");const t=await this.httpClient.post("/user/session/login",{userCode:e.user_code,device_id:this.context.deviceId},{needSign:!1});return t.ok?(this.context.isLogin=!0,this.context.loginUser={userId:t.data.id,secretKey:t.data.key,sessionId:e.user_code},this.applyLoginStatus(),b(null)):(this.singletonLock.releaseLock(),t)}async logout(){if(!this.context.isLogin)return b(null);const e=await this.httpClient.get("/user/logout");return e.ok?(this.afterLogout(),b(null)):e}async afterLogout(){this.context.isLogin=!1,this.context.loginUser=null,this.applyLoginStatus()}getLoginUser(){return null===this.context.loginUser?null:this.context.loginUser.userId}async createSingleChatFeed(e){return await this.httpClient.post("/chat/single",{receiver_id:e})}async deleteFeed(e){return await this.httpClient.post("/feed/delete",{feed_id_list:[e],delete_peer:!0})}async getFeedList(){return b({list:this.feedCache.getAll(),is_sync_completed:this.feedCache.isSyncCompleted()})}async getFeedDetail(e){return b(await this.feedCache.waitFor(e))}async getFeedMemberList(e){const t=await this.feedCache.get(e);return null!==t&&t.chat_member.length>0?await this.httpClient.post("/chat/chatter_info",{chatters:{[t.chat_id]:t.chat_member}}):b([])}getDomain(e){const[t,i]=l,s=A(t),n=A(i);for(const r of e){if(s.test(r.content))return t;if(n.test(r.content))return i}}appendXsid(e){if(!this.context.loginUser?.sessionId)return e;const t=this.context.loginUser.sessionId,i=this.getDomain(e);return i?e.map(e=>{const s=y(e.content,i,e=>((e,t,i)=>{const s=encodeURIComponent(t),n=encodeURIComponent(i),r=e.indexOf("#"),o=r>=0?e.slice(0,r):e,a=r>=0?e.slice(r):"",c=new RegExp(`([?&])${T(s)}=[^&#]*`);if(c.test(o))return o.replace(c,`$1${s}=${n}`)+a;const d=o.includes("?")?"&":"?";return`${o}${d}${s}=${n}${a}`})(e,"xsid",t));return{...e,content:s}}):e}async markFeedMessageAsRead(e){const t=this.feedCache.get(e);if(!t)return b(!1);if(!(await this.httpClient.post("/feed/update",{id:t.id,mark_unread:i.yes})).ok)return b(!1);return(await this.httpClient.post("/message/read",{chat_id:t.chat_id,thread_id:t.thread_id})).ok?b(!0):b(!1)}async getMessagesByIds(e,t){const i=this.feedCache.get(e);if(!i||!Array.isArray(t)||0===t.length)return b([]);const s=await this.httpClient.post("/message/get_by_msgid",{chat_msg_id_map:{[i.chat_id]:t}});if(s.ok){return b(this.appendXsid(s.data[i.chat_id]))}return b([])}async getFeedMessageList(e){const t=await this.getFeedDetail(e.feed_id);if(t.ok&&t.data){const i=t.data,{chat_id:s,first_position:n,last_message_position:r}=i,{positions:o,nextPosition:a,hasMore:c}=(e=>{const t=[];if(e.direction===u.up){let i=e.startPosition??e.maxPosition;for(;t.length<e.limit&&i>=e.minPosition;)t.push(i),i--;const s=i>=e.minPosition;let n;return s&&(n=i),{positions:t,nextPosition:n,hasMore:s}}{let i=e.startPosition??e.minPosition;for(;t.length<e.limit&&i<=e.maxPosition;)t.push(i),i++;const s=i<=e.maxPosition;let n;return s&&(n=i),{positions:t,nextPosition:n,hasMore:s}}})({maxPosition:r,minPosition:n,startPosition:e.message_position,limit:e.limit,direction:e.direction??u.up});if(o.length>0){const e=await this.httpClient.post("/message/get_by_position",{chat_position:{[s]:o}},{needSign:!1});if(e.ok&&e.data[s]){return b({has_more:c,list:this.appendXsid(e.data[s].reverse()),next_message_position:a})}}}return b({has_more:!1,list:[]})}createCustomMessage(e){if(null===this.context.loginUser)return f(_.SDK_ERROR,"not login");const t=this.feedCache.get(e.feed_id);if(null===t)return f(_.SDK_ERROR,"not found feed");const i=(new Date).toISOString();var s;return b({id:"",chat_id:t.chat_id,thread_id:t.thread_id,position:t.last_message_position,sender_id:this.context.loginUser.userId,message_kind_id:o.text,message_type_id:a.custom,send_at:i,edited_at:i,reader_ids:[],unreader_ids:[],hide_ids:[],operation:d.normal,operation_user_id:"0",content:(s={client_msg_id:e.client_msg_id,content:e.content},JSON.stringify({client_msg_id:s.client_msg_id,content:JSON.stringify(s.content)})),reactions:[]})}async sendMessageToFeed(e){if(e.message_type_id===a.custom){const t=C(e.content);return this.httpClient.post("/message/send_custom",{chat_id:e.chat_id,thread_id:e.thread_id,client_id:t.client_msg_id,content:null==t.content?void 0:JSON.stringify(t.content)})}return f(_.SDK_ERROR,"not support")}async sendMessageReadReceipt(e){const t=this.feedCache.get(e.feed_id);return null===t?f(_.SDK_ERROR,"not found feed"):await this.httpClient.post("/message/read",{chat_id:t.chat_id,message_ids:e.message_ids})}async joinRoom(e){return await this.httpClient.post("/liveshow/join",{room_id:e})}async setMute(e){const t=await this.httpClient.post("/feed/update",{id:e.feedId,is_mute:e.isMute?i.yes:i.no});return t.ok?t.data:null}async leaveRoom(e){return await this.httpClient.post("/liveshow/leave",{room_id:e})}async getRoomRecentMessageList(e){const t=await this.httpClient.get("/liveshow/get_recent_message",{room_id:e});return t.ok?b(t.data):t}async sendMessageToRoom(e){return await this.httpClient.post("/liveshow/send_message",{room_id:e.room_id,content:e.content})}}const j=new Map;function H(e,t){let i=j.get(e);return void 0===i&&(i=new K(t),j.set(e,i)),i}const B={parseSystemMessageContent:e=>{const t=S(e);return null!==t?{text:t.text,text_i18n:t.text_i18n}:{}},parseTextMessageContent:e=>{const t=S(e);return null!==t?{text:t.text,client_msg_id:t.client_msg_id}:{}},parseCustomMessageContent:C};export{K as ChatSDK,H as create,g as enums,p as events,m as interfaces,B as utils};
1
+ import e from"axios";import t from"crypto-js";var s,i,n,o,r,a,d,c;!function(e){e[e.yes=1]="yes",e[e.no=0]="no"}(s||(s={})),function(e){e[e.CREATE_FEED=0]="CREATE_FEED",e[e.UPDATE_FEED=1]="UPDATE_FEED",e[e.ADD_MESSAGE=2]="ADD_MESSAGE",e[e.UPDATE_MESSAGE=3]="UPDATE_MESSAGE",e[e.UPDATE_USER_DATA=4]="UPDATE_USER_DATA",e[e.USER_LOGIN=5]="USER_LOGIN",e[e.READ_MESSAGE=6]="READ_MESSAGE",e[e.PONG_MESSAGE=8]="PONG_MESSAGE",e[e.DELETE_MESSAGE=9]="DELETE_MESSAGE",e[e.UPDATE_GROUP=12]="UPDATE_GROUP",e[e.DELETE_GROUP=13]="DELETE_GROUP",e[e.UPDATE_LOGIN_USER=17]="UPDATE_LOGIN_USER",e[e.UPDATE_MESSAGE_REACTION=19]="UPDATE_MESSAGE_REACTION",e[e.ADD_GROUP_MEMBER=21]="ADD_GROUP_MEMBER",e[e.DEL_GROUP_MEMBER=22]="DEL_GROUP_MEMBER",e[e.ADD_CONTACTS=23]="ADD_CONTACTS",e[e.UPDATE_CONTACTS=24]="UPDATE_CONTACTS",e[e.DEL_CONTACTS=25]="DEL_CONTACTS",e[e.BLOCK_USER=26]="BLOCK_USER",e[e.DEVICE_CODE=27]="DEVICE_CODE",e[e.MSG_OPEN_CLOCK=28]="MSG_OPEN_CLOCK",e[e.DELETE_SECRET_CHAT=29]="DELETE_SECRET_CHAT",e[e.DELETE_FEED=30]="DELETE_FEED",e[e.FAVORITE_UPDATE=31]="FAVORITE_UPDATE",e[e.STICKERS_UPDATE=32]="STICKERS_UPDATE",e[e.CUSTOM_STICKERS_UPDATE=33]="CUSTOM_STICKERS_UPDATE",e[e.MANAGE_DEVICE_UPDATE=34]="MANAGE_DEVICE_UPDATE",e[e.MASS_MESSAGE_UPDATE=35]="MASS_MESSAGE_UPDATE",e[e.CHAT_WALLPAPER_DELETE=36]="CHAT_WALLPAPER_DELETE",e[e.CHAT_WALLPAPER_ADD=37]="CHAT_WALLPAPER_ADD",e[e.CONTACT_REQUEST=40]="CONTACT_REQUEST",e[e.USER_PREFERENCE_CHANGE=38]="USER_PREFERENCE_CHANGE",e[e.UPDATE_GROUP_PIN=41]="UPDATE_GROUP_PIN",e[e.RTC_CANCEL=46]="RTC_CANCEL",e[e.ADD_FEED_FOLDER=43]="ADD_FEED_FOLDER",e[e.UPDATE_FEED_FOLDER=44]="UPDATE_FEED_FOLDER",e[e.UPDATE_FOLDER_FEED_LIST=47]="UPDATE_FOLDER_FEED_LIST",e[e.DELETE_FEED_FOLDER=45]="DELETE_FEED_FOLDER",e[e.UPDATE_CHATTER=42]="UPDATE_CHATTER",e[e.PAPER_KEY=48]="PAPER_KEY",e[e.PAPER_KEY_LOG=49]="PAPER_KEY_LOG",e[e.USER_LOGIN_SCAN=50]="USER_LOGIN_SCAN",e[e.RTC_RINGING=51]="RTC_RINGING",e[e.ON_UPDATE_PRIVATE_SETTING=52]="ON_UPDATE_PRIVATE_SETTING",e[e.ON_DELETE_PRIVATE_SETTING=53]="ON_DELETE_PRIVATE_SETTING",e[e.ON_UPDATE_LOGIN_PRIVATE_SETTING=54]="ON_UPDATE_LOGIN_PRIVATE_SETTING",e[e.PUSH_LIVE_MESSAGE=56]="PUSH_LIVE_MESSAGE",e[e.PUSH_SYSTEM_NOTICE=58]="PUSH_SYSTEM_NOTICE",e[e.BIG_PACKAGE_PUSH=126]="BIG_PACKAGE_PUSH",e[e.KICK_OUT_DEVICE=127]="KICK_OUT_DEVICE",e[e.CLEAR_HISTORY=128]="CLEAR_HISTORY",e[e.CLEAR_DATA=255]="CLEAR_DATA"}(i||(i={})),function(e){e[e.singleChat=1]="singleChat",e[e.groupChat=2]="groupChat"}(n||(n={})),function(e){e[e.normal=0]="normal",e[e.thread=1]="thread"}(o||(o={})),function(e){e[e.text=0]="text",e[e.system=1]="system"}(r||(r={})),function(e){e[e.text=0]="text",e[e.image=1]="image",e[e.card=2]="card",e[e.audio=3]="audio",e[e.video=4]="video",e[e.file=5]="file",e[e.mergeForward=6]="mergeForward",e[e.sticker=7]="sticker",e[e.richText=8]="richText",e[e.custom=9]="custom"}(a||(a={})),function(e){e[e.Owner=1]="Owner",e[e.Admin=2]="Admin",e[e.Common=3]="Common",e[e.Bot=4]="Bot"}(d||(d={})),function(e){e[e.normal=0]="normal",e[e.recall=1]="recall",e[e.destroy=2]="destroy",e[e.edit=3]="edit",e[e.main_delete=4]="main_delete"}(c||(c={}));const l=["api-coco.typex.im","api-tx.typex-test.cn"];var h,u,g;!function(e){e.error="ERROR",e.warning="WARNING",e.info="INFO"}(h||(h={})),function(e){e[e.SDK_ERROR=-1e4]="SDK_ERROR",e[e.NETWORK_ERROR=-9999]="NETWORK_ERROR",e[e.MAKE_SIGN_FAIL=-9998]="MAKE_SIGN_FAIL",e[e.REQUEST_SINGLETON_LOCK_FAIL=-9997]="REQUEST_SINGLETON_LOCK_FAIL",e[e.SUCCESS=0]="SUCCESS"}(u||(u={})),function(e){e[e.up=0]="up",e[e.down=1]="down"}(g||(g={}));var _=Object.freeze({__proto__:null,get Bool(){return s},get ChatType(){return n},get FeedType(){return o},get GroupRole(){return d},get HttpClientResponseCode(){return u},get LogLevel(){return h},get MessageKind(){return r},get MessageOperation(){return c},get MessageType(){return a},get PushMessageType(){return i},RESOURCE_AUTH_DOMAINS:l,get RequestDirection(){return g}});const p={SDK_READY:"sdkReady",SDK_NOT_READY:"sdkNotReady",FEED_LIST_UPDATED:"feedListUpdated",MESSAGE_RECEIVED:"messageReceived",MESSAGE_RECALLED:"messageRecalled",MESSAGE_EDITED:"messageEdited",MESSAGE_DESTROYED:"messageDestroyed",MESSAGE_REACTION_UPDATED:"messageReactionUpdated",MESSAGE_RECEIPT_RECEIVED:"messageReceiptReceived",MESSAGE_OPEN_CLOCK:"messageOpenClock",ROOM_MESSAGE_RECEIVED:"roomMessageReceived",SYSTEM_NOTICE_RECEIVED:"systemNoticeReceived"};var E=Object.freeze({__proto__:null,CHAT_SDK_EVENT:p}),f=Object.freeze({__proto__:null});function m(e,t){return{ok:!1,code:e,msg:t}}function b(e){return{ok:!0,data:e}}const S=e=>{try{return null==e||"string"!=typeof e||0===e.length?null:JSON.parse(e)}catch{return null}},y=e=>{const t=S(e);if(null!==t){let e;return null!=t.content&&(e=S(t.content)??void 0),{client_msg_id:t.client_msg_id,content:e}}return{}},C=e=>e.replace(/[.*+?^${}()|[\]\\]/g,"\\$&"),T=e=>new RegExp(`https?:\\\\?/\\\\?/${C(e)}(?:\\\\.|[^"\\\\\\s])*`,"g"),v=(e,t,s)=>{if(!e||"string"!=typeof e)return e;const i=T(t);return e.replace(i,e=>{const t=(e=>{try{return JSON.parse(`"${e}"`)}catch{return e}})(e),i=s(t);return"string"!=typeof i||i===t?e:(n=i,JSON.stringify(n).slice(1,-1));var n})};class w{constructor(e){Object.defineProperty(this,"all",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),this.all=e||new Map}on(e,t){const s=this.all.get(e);return s?s.push(t):this.all.set(e,[t]),()=>{this.off(e,t)}}off(e,t){const s=this.all.get(e);s&&(t?s.splice(s.indexOf(t)>>>0,1):this.all.set(e,[]))}emit(e,t){let s=this.all.get(e);s&&s.slice().map(e=>{e(t)}),s=this.all.get("*"),s&&s.slice().map(s=>{s(e,t)})}once(e,t){if("*"===e){const s=(e,i)=>{t(e,i),this.off("*",s)};this.on(e,s)}else{const s=i=>{t(i),this.off(e,s)};this.on(e,s)}}}function A(e){const t=(new TextEncoder).encode(e);let s="";for(const e of t)s+=String.fromCharCode(e);return btoa(s).replace(/\+/g,"-").replace(/\//g,"_").replace(/=+$/,"")}class R extends w{constructor(e){super(),Object.defineProperty(this,"url",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"token",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"logger",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"ws",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"destroyed",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"pingTimeout",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"pongTimeout",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"reConnectTimeout",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),this.url=e.url,this.token=e.token,this.logger=e.logger,this.ws=null,this.destroyed=!1,this.pingTimeout=null,this.pongTimeout=null,this.reConnectTimeout=null,this.reConnect=this.reConnect.bind(this),window.addEventListener("online",this.reConnect),this.connect()}disconnect(){this.ws&&(this.ws.onopen=null,this.ws.onerror=null,this.ws.onmessage=null,this.ws.onclose=null,this.ws.close(),this.ws=null),null!==this.pingTimeout&&(clearTimeout(this.pingTimeout),this.pingTimeout=null),null!==this.pongTimeout&&(clearTimeout(this.pongTimeout),this.pongTimeout=null),null!==this.reConnectTimeout&&(clearTimeout(this.reConnectTimeout),this.reConnectTimeout=null)}connect(){if(this.ws)return void this.logger.warn("ReConnectWebsocket try connect but already connected");const e=new URL(this.url);e.searchParams.set("platform","web");const t=new WebSocket(e.toString(),["typex.im.auth.v1",`typex.im.auth.b64url.${A(this.token)}`]);this.ws=t,t.onopen=()=>{this.delaySendPing()},t.onerror=e=>{this.logger.info("ReConnectWebsocket error",e)},t.onmessage=e=>{try{const t=JSON.parse(e.data);if(t.type===i.PONG_MESSAGE?null!==this.pongTimeout&&(clearTimeout(this.pongTimeout),this.pongTimeout=null,this.delaySendPing()):this.sendAck(t.id),t.type===i.BIG_PACKAGE_PUSH)for(const e of t.content.big_push)this.emit("message",e);else this.emit("message",t)}catch(e){this.logger.error("ReConnectWebsocket message parse failed",e)}},t.onclose=e=>{4001===e.code?this.kickOff():this.reConnect()}}reConnect(){this.disconnect(),this.destroyed||(this.reConnectTimeout=setTimeout(()=>{this.reConnectTimeout=null,this.connect()},5e3))}send(e){if(this.destroyed)return!1;if(!this.ws)return this.logger.warn("ReConnectWebsocket send before connect"),!1;try{return this.ws.readyState!==this.ws.OPEN?(this.logger.warn("ReConnectWebsocket send but not open",this.ws.readyState),!1):(this.ws.send(JSON.stringify(e)),!0)}catch(e){return this.logger.warn("ReConnectWebsocket send error",e),!1}}sendAck(e){this.send({type:1,ids:[e]})}destroy(){this.destroyed||(this.destroyed=!0,this.disconnect(),window.removeEventListener("online",this.reConnect))}delaySendPing(){null!==this.pingTimeout&&(clearTimeout(this.pingTimeout),this.pingTimeout=null),this.pingTimeout=setTimeout(()=>{this.pingTimeout=null;this.send({type:0})?this.waitPong():this.reConnect()},2e4)}waitPong(){this.pongTimeout=setTimeout(()=>{this.logger.info("ReConnectWebsocket pong timeout"),this.reConnect()},1e4)}kickOff(){this.destroy(),this.emit("kickoff")}}class O extends w{constructor(e){super(),Object.defineProperty(this,"host",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"context",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"logger",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"ws",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),this.host=e.host,this.context=e.context,this.logger=e.logger,this.ws=null}connect(){null!==this.context.loginUser?this.ws?this.logger.warn("BusinessWebsocket try connect but already connected"):(this.ws=new R({url:`${this.host}/ws`,token:this.context.loginUser.sessionId,logger:this.logger}),this.ws.on("message",e=>{this.emit("message",e)}),this.ws.on("kickoff",()=>{this.emit("kickoff")})):this.logger.warn("BusinessWebsocket try connect but not login")}disconnect(){this.ws?(this.ws.destroy(),this.ws=null):this.logger.info("BusinessWebsocket already disconnected")}}class D{constructor(){Object.defineProperty(this,"syncCompleted",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"map",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"chatMap",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"threadMap",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"targetMap",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"list",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"waitMap",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),this.syncCompleted=!1,this.map=new Map,this.chatMap=new Map,this.threadMap=new Map,this.targetMap=new Map,this.waitMap=new Map,this.list=[]}getAll(){const e=[];for(const t of this.list){const s=this.map.get(t);s&&e.push(s)}return e}get(e){return this.map.get(e)??null}getByChat(e,t){let s;return s=t&&"0"!==t?this.threadMap.get(t):this.chatMap.get(e),void 0!==s?this.get(s):null}getByTargetId(e){const t=this.targetMap.get(e);if(void 0===t)return[];const s=[];for(const e of t){const t=this.get(e);null!==t&&s.push(t)}return s}async waitFor(e){const t=this.get(e);if(t)return t;if(this.syncCompleted)return null;let s=this.waitMap.get(e);return s||(s=(()=>{let e=()=>{};return{promise:new Promise(t=>{e=t}),resolve:e}})(),this.waitMap.set(e,s)),await s.promise,this.get(e)}resolveWait(e){const t=this.waitMap.get(e);t&&(t.resolve(),this.waitMap.delete(e))}removeFromList(e){const t=this.list.indexOf(e);t>-1&&this.list.splice(t,1)}remove(e){const t=this.map.get(e);if(t){if(this.map.delete(e),t.feed_type===o.thread)this.threadMap.delete(t.thread_id);else if(this.chatMap.delete(t.chat_id),t.target_id&&"0"!==t.target_id){const e=this.targetMap.get(t.target_id);void 0!==e&&(e.delete(t.id),0===e.size&&this.targetMap.delete(t.target_id))}return this.removeFromList(e),!0}return!1}beforeSave(e){if(this.map.has(e.id))this.removeFromList(e.id);else if(e.feed_type===o.thread)this.threadMap.set(e.thread_id,e.id);else if(this.chatMap.set(e.chat_id,e.id),e.target_id&&"0"!==e.target_id){if(!this.targetMap.has(e.target_id)){const t=new Set;this.targetMap.set(e.target_id,t)}this.targetMap.get(e.target_id)?.add(e.id)}this.map.set(e.id,e)}afterSave(e){this.resolveWait(e.id)}push(e){this.beforeSave(e),this.list.push(e.id),this.afterSave(e)}unshift(e){this.beforeSave(e),this.list.unshift(e.id),this.afterSave(e)}update(e){this.map.has(e.id)&&this.map.set(e.id,e)}markSyncComplete(){this.syncCompleted=!0;for(const[e,t]of this.waitMap)t.resolve();this.waitMap.clear()}isSyncCompleted(){return this.syncCompleted}reset(){this.syncCompleted=!1,this.map.clear(),this.chatMap.clear(),this.threadMap.clear(),this.targetMap.clear(),this.waitMap.clear(),this.list=[]}}function P(e){return(new TextEncoder).encode(e).buffer}async function L(e,s){return window.crypto&&window.crypto.subtle?await async function(e,t){const s=P(t),i=P(e),n=await crypto.subtle.importKey("raw",s,{name:"HMAC",hash:{name:"SHA-256"}},!1,["sign"]),o=await crypto.subtle.sign("HMAC",n,i);return Array.from(new Uint8Array(o)).map(e=>e.toString(16).padStart(2,"0")).join("")}(e,s):function(e,s){return t.HmacSHA256(e,s).toString(t.enc.Hex)}(e,s)}const M=e=>{if(null==e)return"";if("object"!=typeof e||Array.isArray(e)){if(Array.isArray(e)){let t="";for(const s of e)t+=M(s);return t}return"string"==typeof e?e:String(e)}{const t=Object.keys(e).sort();let s="";for(const i of t)s+=M(e[i]);return s}};function I(){return m(u.MAKE_SIGN_FAIL,"make sign fail")}class k{constructor(t){Object.defineProperty(this,"api",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"context",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"logger",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),this.api=e.create({baseURL:t.host,headers:{"x-developer":t.developer},withCredentials:!0}),this.context=t.context,this.logger=t.logger}async request(e){try{const{needSign:t=!0,...s}=e;if(s.headers||(s.headers={}),s.headers.platform="web",t&&"POST"===e.method?.toUpperCase()&&s.data){if(null===this.context.loginUser)return this.logger.warn("HttpClient needs make sign but not login"),I();try{const e=await(async(e,t)=>{const s=await M(e);return await L(s,t)})(s.data,this.context.loginUser.secretKey);s.headers.sign=e}catch(e){return this.logger.error("HttpClient make sign error",e),I()}}this.context.loginUser&&(s.headers["X-Sid"]=this.context.loginUser.sessionId);const i=await this.api(s),n=i.data;return n.code===u.SUCCESS?{ok:!0,data:n.data}:(this.logger.info("HttpClient server error",i),{ok:!1,code:n.code,msg:n.msg,msg_i18n:n.msg_i18n})}catch{return{ok:!1,code:u.NETWORK_ERROR,msg:"network error"}}}get(e,t,s){return this.request({url:e,method:"GET",params:t,...s})}post(e,t,s){return this.request({url:e,method:"POST",data:t,...s})}}function U(e){return`${e}`.padStart(2,"0")}class x{constructor(){Object.defineProperty(this,"level",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"logHandler",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),this.level=h.error,this.logHandler=this.createLogHandler()}getPriority(e){switch(e){case h.error:return 3;case h.warning:return 2;case h.info:return 1;default:return 0}}createLogHandler(){return(e,...t)=>{const s=new Date,i=`TypeX >> [${`${s.getFullYear()}-${U(s.getMonth()+1)}-${U(s.getDate())} ${U(s.getHours())}:${U(s.getMinutes())}:${U(s.getSeconds())}.${s.getMilliseconds()}`}]`;switch(e){case h.error:console.error(i,"[ERR]",...t);break;case h.warning:console.warn(i,"[WARN]",...t);break;case h.info:console.info(i,"[INFO]",...t);break;default:console.log(i,...t)}}}log(e,...t){this.getPriority(e)>=this.getPriority(this.level)&&this.logHandler(e,...t)}setLogLevel(e){this.level=e,this.logHandler=this.createLogHandler()}info(...e){this.log(h.info,...e)}warn(...e){this.log(h.warning,...e)}error(...e){this.log(h.error,...e)}}class G{constructor(e){Object.defineProperty(this,"context",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"logger",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"emitter",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"feedCache",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"handleKickoff",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),this.context=e.context,this.logger=e.logger,this.emitter=e.emitter,this.feedCache=e.feedCache,this.handleKickoff=e.onKickoff}emitFeedListUpdated(){this.emitter.emit(p.FEED_LIST_UPDATED,{list:this.feedCache.getAll(),is_sync_completed:this.feedCache.isSyncCompleted()})}processCreateFeed(e){this.feedCache.unshift(e.content),this.emitFeedListUpdated()}processUpdateFeed(e){const t=e.content,s=this.feedCache.getByChat(t.chat_id,t.thread_id);if(null===s)return;const i={...s,...t};this.feedCache.update(i),this.emitFeedListUpdated()}processDeleteFeed(e){this.feedCache.remove(e.content.id)&&this.emitFeedListUpdated()}processAddMessage(e){if(null===this.context.loginUser)return;const t=this.context.loginUser.userId,i=e.content;if(i.hide_ids.includes(t))return;const n=this.feedCache.getByChat(i.chat_id,i.thread_id);if(null!==n){if(i.no_last_msg!==s.yes){let e=!1,o=!1;const a={};if(i.message_kind_id!==r.system&&i.sender_id!==t&&i.no_read!==s.yes){e=!0;const t=new Set(n.unread_message_ids);t.add(i.id),a.unread_message_ids=[...t],a.badge=t.size}if(n.last_message_position<i.position&&(e=!0,o=!0,a.last_message_id=i.id,a.last_message_position=i.position,a.last_message_sender_id=i.sender_id,a.last_message_send_at=i.send_at,a.last_message_kind_id=i.message_kind_id,a.last_message_type_id=i.message_type_id,a.last_message=i.content,a.last_message_operation=i.operation,a.last_message_operation_user_id=i.operation_user_id),e){const e={...n,...a};o?this.feedCache.unshift(e):this.feedCache.update(e),this.emitFeedListUpdated()}}this.emitter.emit(p.MESSAGE_RECEIVED,{feed_id:n.id,message:i})}}processUpdateMessage(e){const t=e.content,s=this.feedCache.getByChat(t.chat_id,t.thread_id);if(null!==s&&null!=t.operation){let e=!1;const i={};if(t.operation===c.recall||t.operation===c.destroy){if(null!=s.unread_message_ids&&s.unread_message_ids.includes(t.id)){e=!0;const n=new Set(s.unread_message_ids);n.delete(t.id),i.unread_message_ids=[...n],i.badge=i.unread_message_ids.length}s.last_message_id===t.id&&(e=!0,i.last_message=t.content??"{}",i.last_message_operation=t.operation,i.last_message_operation_user_id=t.operation_user_id??"0")}else t.operation===c.edit&&s.last_message_id===t.id&&(e=!0,i.last_message_kind_id=t.message_kind_id,i.last_message_type_id=t.message_type_id,i.last_message=t.content,i.last_message_operation=t.operation,i.last_message_operation_user_id=t.operation_user_id);e&&(this.feedCache.update({...s,...i}),this.emitFeedListUpdated()),t.operation===c.recall?this.emitter.emit(p.MESSAGE_RECALLED,{message_ids:[t.id]}):t.operation===c.edit?null!=t.content&&null!=t.edited_at&&null!=t.message_kind_id&&null!=t.message_type_id&&null!=t.operation_user_id&&this.emitter.emit(p.MESSAGE_EDITED,{chat_id:t.chat_id,content:t.content,edited_at:t.edited_at,id:t.id,message_kind_id:t.message_kind_id,message_type_id:t.message_type_id,operation:t.operation,operation_user_id:t.operation_user_id,thread_id:t.thread_id}):t.operation===c.destroy&&this.emitter.emit(p.MESSAGE_DESTROYED,{feed_id:s.id,message_ids:[t.id]})}}processDeleteMessage(e){const t=e.content,s=this.feedCache.getByChat(t.chat_id,t.thread_id);if(null===s)return;let i=!1;const n={};s.last_message_id===t.id&&(i=!0,n.last_message=t.content??"{}",n.last_message_operation=t.operation,n.last_message_operation_user_id=t.operation_user_id??"0"),i&&(this.feedCache.update({...s,...n}),this.emitFeedListUpdated()),this.emitter.emit(p.MESSAGE_DESTROYED,{feed_id:s.id,message_ids:[t.id]})}processOpenClockMessage(e){const t=e.content,s=this.feedCache.getByChat(t.chat_id,t.thread_id);if(null!==s&&Array.isArray(t.msgs_open_clock)){const e=t.msgs_open_clock.map(e=>e.message_id);this.emitter.emit(p.MESSAGE_OPEN_CLOCK,{feed_id:s.id,message_ids:e})}}processPushLiveMessage(e){this.emitter.emit(p.ROOM_MESSAGE_RECEIVED,{room_id:e.content.room_id,content:e.content.message})}processPushSystemNotice(e){this.emitter.emit(p.SYSTEM_NOTICE_RECEIVED,{content:e.content})}processReadMessage(e){if(null===this.context.loginUser)return;const t=this.context.loginUser.userId,s=e.content,i=this.feedCache.getByChat(s.chat_id,s.thread_id);if(null===i)return;let n=!1;const o={};if(s.reader_ids.includes(t)&&s.message_ids.length>0){n=!0;const e=new Set(i.unread_message_ids);s.message_ids.forEach(t=>{e.delete(t)}),o.unread_message_ids=[...e],o.badge=e.size}n&&(this.feedCache.update({...i,...o}),this.emitFeedListUpdated()),this.emitter.emit(p.MESSAGE_RECEIPT_RECEIVED,{feed_id:i.id,message_ids:s.message_ids,reader_user_ids:s.reader_ids})}processKickOutDevice(){this.handleKickoff()}processGroupMember(e){const t=e.content,s=this.feedCache.getByChat(t.chat_id,"0");if(null===s)return;const n=new Set(s.chat_member),o=e.type===i.ADD_GROUP_MEMBER,r=e.type===i.DEL_GROUP_MEMBER;t.chat_member.forEach(e=>{o?n.add(e.chat_id):r&&n.delete(e.chat_id)}),this.feedCache.update({...s,chat_member:[...n]}),this.emitFeedListUpdated()}processUpdateGroup(e){const t=e.content,s=this.feedCache.getByChat(t.chat_id,"0");if(null===s)return;let i=!1;const n={};null!=t.avatar&&(i=!0,n.avatar=t.avatar),null!=t.name&&(i=!0,n.name=t.name),i&&(this.feedCache.update({...s,...n}),this.emitFeedListUpdated())}processUpdateUserData(e){const t=e.content,s=this.feedCache.getByTargetId(t.id);if(s.length>0){const e={};if(null!=t.avatar&&(e.avatar=t.avatar),null!=t.first_name||null!=t.last_name){let s=t.first_name??"";null!=t.last_name&&(s=s.length>0?`${s} ${t.last_name}`:t.last_name),e.name=s}for(const t of s)this.feedCache.update({...t,...e});this.emitFeedListUpdated()}}processUpdateMessageReaction(e){const t=e.content,s=this.feedCache.getByChat(t.chat_id,t.thread_id);null!==s&&this.emitter.emit(p.MESSAGE_REACTION_UPDATED,{feed_id:s.id,message_id:t.message_id,reactions:t.reactions})}process(e){switch(this.logger.info("PushMessageProcessor process",e),e.type){case i.CREATE_FEED:this.processCreateFeed(e);break;case i.UPDATE_FEED:this.processUpdateFeed(e);break;case i.DELETE_FEED:this.processDeleteFeed(e);break;case i.ADD_MESSAGE:this.processAddMessage(e);break;case i.UPDATE_MESSAGE:this.processUpdateMessage(e);break;case i.DELETE_MESSAGE:this.processDeleteMessage(e);break;case i.PUSH_LIVE_MESSAGE:this.processPushLiveMessage(e);break;case i.MSG_OPEN_CLOCK:this.processOpenClockMessage(e);break;case i.PUSH_SYSTEM_NOTICE:this.processPushSystemNotice(e);break;case i.READ_MESSAGE:this.processReadMessage(e);break;case i.KICK_OUT_DEVICE:this.processKickOutDevice();break;case i.ADD_GROUP_MEMBER:case i.DEL_GROUP_MEMBER:this.processGroupMember(e);break;case i.UPDATE_GROUP:this.processUpdateGroup(e);break;case i.UPDATE_USER_DATA:this.processUpdateUserData(e);break;case i.UPDATE_MESSAGE_REACTION:this.processUpdateMessageReaction(e)}}}const N=50;function F(e){return new Promise(t=>{setTimeout(t,e)})}class j{constructor(){Object.defineProperty(this,"obtained",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"abortLockObtain",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),this.obtained=!1,this.abortLockObtain=null}async requestLock(e={}){const{timeoutMs:t=0,retryIntervalMs:s=N}=e,i=Date.now();for(;;){if(await this.requestLockOnce())return!0;if(t<=0)return!1;const e=t-(Date.now()-i);if(e<=0)return!1;await F(Math.min(s,e))}}async requestLockOnce(){if(this.obtained)return!0;if("undefined"==typeof navigator||!navigator.locks)return!1;let e=()=>{};const t=new Promise(t=>{e=t}),s=new Promise(e=>{this.abortLockObtain=e});try{navigator.locks.request("typex-sdk",{ifAvailable:!0},async t=>{t?(this.obtained=!0,e(!0),await s):(this.abortLockObtain=null,e(!1))}).catch(()=>{this.abortLockObtain=null,e(!1)})}catch{this.abortLockObtain=null,e(!1)}return await t}releaseLock(){this.obtained=!1,null!==this.abortLockObtain&&(this.abortLockObtain(),this.abortLockObtain=null)}}class K{static set(e){localStorage.setItem(this.key,JSON.stringify(e))}static get(){try{const e=localStorage.getItem(this.key);if(!e)return null;return JSON.parse(e)}catch{return null}}static clear(){localStorage.removeItem(this.key)}}Object.defineProperty(K,"key",{enumerable:!0,configurable:!0,writable:!0,value:"__typex_sdk_data__"});const q="__typex_sdk_tab_session_message__";function H(){return"undefined"!=typeof crypto&&"randomUUID"in crypto?crypto.randomUUID():`${Date.now()}-${Math.random().toString(36).slice(2)}`}class B{constructor(e){Object.defineProperty(this,"tabId",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"channel",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"closed",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"handledTakeoverIds",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"handledSessionRequestIds",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"pendingSessionRequests",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"onTakeoverRequest",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"getCurrentSession",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"logger",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),this.tabId=H(),this.channel=null,this.closed=!1,this.handledTakeoverIds=new Set,this.handledSessionRequestIds=new Set,this.pendingSessionRequests=new Map,this.onTakeoverRequest=e.onTakeoverRequest,this.getCurrentSession=e.getCurrentSession??null,this.logger=e.logger??null,this.handleBroadcastMessage=this.handleBroadcastMessage.bind(this),this.handleStorageMessage=this.handleStorageMessage.bind(this),"undefined"!=typeof BroadcastChannel&&(this.channel=new BroadcastChannel("typex-sdk-tab-session"),this.channel.onmessage=this.handleBroadcastMessage),"undefined"!=typeof window&&window.addEventListener("storage",this.handleStorageMessage)}requestTakeover(){this.publish({type:"takeover",senderTabId:this.tabId,takeoverId:H(),createdAt:Date.now()})}requestCurrentSession(e=500){if(this.closed)return Promise.resolve(null);const t=H();return new Promise(s=>{const i=setTimeout(()=>{this.pendingSessionRequests.delete(t),s(null)},e);this.pendingSessionRequests.set(t,{resolve:s,timeout:i}),this.publish({type:"session-request",senderTabId:this.tabId,requestId:t,createdAt:Date.now()})})}destroy(){this.closed||(this.closed=!0,this.pendingSessionRequests.forEach(e=>{clearTimeout(e.timeout),e.resolve(null)}),this.pendingSessionRequests.clear(),this.channel&&(this.channel.close(),this.channel=null),"undefined"!=typeof window&&window.removeEventListener("storage",this.handleStorageMessage))}publish(e){if(!this.closed&&(this.channel&&this.channel.postMessage(e),"session-response"!==e.type&&"undefined"!=typeof localStorage))try{localStorage.setItem(q,JSON.stringify({...e,storageNonce:H()}))}catch(e){this.logger?.warn("TabSessionCoordinator storage publish failed",e)}}handleBroadcastMessage(e){this.handleMessage(e.data)}handleStorageMessage(e){if(e.key===q&&e.newValue)try{this.handleMessage(JSON.parse(e.newValue))}catch(e){this.logger?.warn("TabSessionCoordinator storage parse failed",e)}}handleMessage(e){if(!this.closed&&function(e){if(!e||"object"!=typeof e)return!1;const t=e;return"string"==typeof t.senderTabId&&("takeover"===t.type?"string"==typeof t.takeoverId&&"number"==typeof t.createdAt:"session-request"===t.type?"string"==typeof t.requestId&&"number"==typeof t.createdAt:"session-response"===t.type&&"string"==typeof t.requesterTabId&&"string"==typeof t.requestId&&"number"==typeof t.createdAt&&function(e){if(!e||"object"!=typeof e)return!1;const t=e,s=t.loginUser;return(null===t.deviceId||"string"==typeof t.deviceId)&&!!s&&"string"==typeof s.userId&&"string"==typeof s.secretKey&&"string"==typeof s.sessionId}(t.session))}(e)&&e.senderTabId!==this.tabId){if("takeover"===e.type){if(this.handledTakeoverIds.has(e.takeoverId))return;return this.handledTakeoverIds.add(e.takeoverId),void this.onTakeoverRequest()}if("session-request"===e.type){const t=`${e.senderTabId}:${e.requestId}`;if(this.handledSessionRequestIds.has(t))return;this.handledSessionRequestIds.add(t);const s=this.getCurrentSession?.();if(!s)return;return void this.publish({type:"session-response",senderTabId:this.tabId,requesterTabId:e.senderTabId,requestId:e.requestId,createdAt:Date.now(),session:s})}if("session-response"===e.type){if(e.requesterTabId!==this.tabId)return;const t=this.pendingSessionRequests.get(e.requestId);if(!t)return;clearTimeout(t.timeout),this.pendingSessionRequests.delete(e.requestId),t.resolve(e.session)}}}}class ${constructor(){Object.defineProperty(this,"version",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),this.version=0}increment(){this.version++}get(){return this.version}check(e){return e===this.version}}class V extends w{constructor(e){super(),Object.defineProperty(this,"context",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"version",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"singletonLock",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"tabSessionCoordinator",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"restoreLoginPromise",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"logger",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"httpClient",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"feedCache",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"ws",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"pushMessageProcessor",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),this.context={isLogin:!1,loginUser:null,isReady:!1,deviceId:null},this.version=new $,this.singletonLock=new j,this.logger=new x,this.restoreLoginPromise=null,this.tabSessionCoordinator=new B({logger:this.logger,getCurrentSession:()=>this.getTransferableLoginSession(),onTakeoverRequest:()=>{this.deactivateByTakeover()}}),this.httpClient=new k({host:e.httpHost,context:this.context,logger:this.logger,developer:e.developer}),this.feedCache=new D,this.ws=new O({host:e.websocketHost,context:this.context,logger:this.logger}),this.pushMessageProcessor=new G({context:this.context,logger:this.logger,emitter:this,feedCache:this.feedCache,onKickoff:()=>{this.afterLogout()}}),this.init()}init(){this.loadContext(),this.ws.on("message",e=>{this.pushMessageProcessor.process(e)}),this.ws.on("kickoff",()=>{this.afterLogout()}),setTimeout(()=>{this.restoreLoginFromActiveTab()},0)}getTransferableLoginSession(){return this.context.isLogin&&null!==this.context.loginUser?{deviceId:this.context.deviceId,loginUser:{...this.context.loginUser}}:null}async restoreLoginFromActiveTab(){if(this.restoreLoginPromise)return this.restoreLoginPromise;this.restoreLoginPromise=this.doRestoreLoginFromActiveTab();try{return await this.restoreLoginPromise}finally{this.restoreLoginPromise=null}}async doRestoreLoginFromActiveTab(){if(this.context.isLogin)return!0;const e=await this.tabSessionCoordinator.requestCurrentSession(500);if(!e||this.context.isLogin)return this.context.isLogin;this.tabSessionCoordinator.requestTakeover();return!await this.singletonLock.requestLock({timeoutMs:3e3,retryIntervalMs:50})||this.context.isLogin?this.context.isLogin:(this.context.isLogin=!0,this.context.loginUser=e.loginUser,e.deviceId&&(this.context.deviceId=e.deviceId),this.applyLoginStatus(),!0)}async requestDeviceId(){if(this.context.deviceId)return!0;const e=await this.httpClient.post("/device_api/device_id",{platform:"web",hash_str:""},{needSign:!1});return!!e.ok&&(this.context.deviceId=e.data,this.saveContext(),!0)}saveContext(){const{context:e}=this;K.set({deviceId:e.deviceId})}loadContext(){const e=K.get();e&&e.deviceId&&(this.context.deviceId=e.deviceId)}applyLoginStatus(){this.version.increment(),this.saveContext(),this.context.isLogin?(this.ws.connect(),this.loadFeedList(),this.context.isReady=!0,this.emit(p.SDK_READY)):(this.ws.disconnect(),this.feedCache.reset(),this.singletonLock.releaseLock(),this.context.isReady=!1,this.emit(p.SDK_NOT_READY))}async loadFeedList(){const e=this.version.get(),t={refresh_at:null,feed_id:null};for(;;){const s=await this.httpClient.get("/feed",{limit:500,last_refresh_at:t.refresh_at??void 0,last_feed_id:t.feed_id??void 0});if(!this.version.check(e))break;if(!s.ok||null===s.data)break;if(t.refresh_at=s.data.refresh_at,t.feed_id=s.data.last_feed_id,(s.data.feed_list??[]).forEach(e=>{this.feedCache.push(e)}),!s.data.has_more)break}this.version.check(e)&&(this.feedCache.markSyncComplete(),this.emit(p.FEED_LIST_UPDATED,{list:this.feedCache.getAll(),is_sync_completed:!0}))}isReady(){return this.context.isReady}setLogLevel(e){this.logger.setLogLevel(e)}async login(e){if(this.context.isLogin)return b(null);if(await this.restoreLoginFromActiveTab()||this.context.isLogin)return b(null);if(await this.requestDeviceId(),!this.context.deviceId)return this.logger.error("Get deviceId failed"),m(u.SDK_ERROR,"Get deviceId failed");const t=await this.httpClient.post("/user/session/login",{userCode:e.user_code,device_id:this.context.deviceId},{needSign:!1});if(!t.ok)return t;this.tabSessionCoordinator.requestTakeover();return await this.singletonLock.requestLock({timeoutMs:3e3,retryIntervalMs:50})?(this.context.isLogin=!0,this.context.loginUser={userId:t.data.id,secretKey:t.data.key,sessionId:e.user_code},this.applyLoginStatus(),b(null)):(this.logger.error("Another active TypeX SDK instance detected"),m(u.REQUEST_SINGLETON_LOCK_FAIL,"Another active TypeX SDK instance detected"))}async logout(){if(!this.context.isLogin)return b(null);const e=await this.httpClient.get("/user/logout");return e.ok?(this.afterLogout(),b(null)):e}async afterLogout(){this.context.isLogin=!1,this.context.loginUser=null,this.applyLoginStatus()}deactivateByTakeover(){this.context.isLogin||this.context.isReady?(this.logger.info("Current TypeX SDK instance deactivated by another tab"),this.afterLogout()):this.singletonLock.releaseLock()}getLoginUser(){return null===this.context.loginUser?null:this.context.loginUser.userId}async createSingleChatFeed(e){return await this.httpClient.post("/chat/single",{receiver_id:e})}async deleteFeed(e){return await this.httpClient.post("/feed/delete",{feed_id_list:[e],delete_peer:!0})}async getFeedList(){return b({list:this.feedCache.getAll(),is_sync_completed:this.feedCache.isSyncCompleted()})}async getFeedDetail(e){return b(await this.feedCache.waitFor(e))}async getFeedMemberList(e){const t=await this.feedCache.get(e);return null!==t&&t.chat_member.length>0?await this.httpClient.post("/chat/chatter_info",{chatters:{[t.chat_id]:t.chat_member}}):b([])}async getUserByUids(e){const t=await this.httpClient.post("/user/users_info",e);return t.ok?b(t.data.map(e=>({id:e.id}))):t}getDomain(e){const[t,s]=l,i=T(t),n=T(s);for(const o of e){if(i.test(o.content))return t;if(n.test(o.content))return s}}appendXsid(e){if(!this.context.loginUser?.sessionId)return e;const t=this.context.loginUser.sessionId,s=this.getDomain(e);return s?e.map(e=>{const i=v(e.content,s,e=>((e,t,s)=>{const i=encodeURIComponent(t),n=encodeURIComponent(s),o=e.indexOf("#"),r=o>=0?e.slice(0,o):e,a=o>=0?e.slice(o):"",d=new RegExp(`([?&])${C(i)}=[^&#]*`);if(d.test(r))return r.replace(d,`$1${i}=${n}`)+a;const c=r.includes("?")?"&":"?";return`${r}${c}${i}=${n}${a}`})(e,"xsid",t));return{...e,content:i}}):e}async markFeedMessageAsRead(e){const t=this.feedCache.get(e);if(!t)return b(!1);if(!(await this.httpClient.post("/feed/update",{id:t.id,mark_unread:s.yes})).ok)return b(!1);return(await this.httpClient.post("/message/read",{chat_id:t.chat_id,thread_id:t.thread_id})).ok?b(!0):b(!1)}async getMessagesByIds(e,t){const s=this.feedCache.get(e);if(!s||!Array.isArray(t)||0===t.length)return b([]);const i=await this.httpClient.post("/message/get_by_msgid",{chat_msg_id_map:{[s.chat_id]:t}});if(i.ok){return b(this.appendXsid(i.data[s.chat_id]))}return b([])}async getFeedMessageList(e){const t=await this.getFeedDetail(e.feed_id);if(t.ok&&t.data){const s=t.data,{chat_id:i,first_position:n,last_message_position:o}=s,{positions:r,nextPosition:a,hasMore:d}=(e=>{const t=[];if(e.direction===g.up){let s=e.startPosition??e.maxPosition;for(;t.length<e.limit&&s>=e.minPosition;)t.push(s),s--;const i=s>=e.minPosition;let n;return i&&(n=s),{positions:t,nextPosition:n,hasMore:i}}{let s=e.startPosition??e.minPosition;for(;t.length<e.limit&&s<=e.maxPosition;)t.push(s),s++;const i=s<=e.maxPosition;let n;return i&&(n=s),{positions:t,nextPosition:n,hasMore:i}}})({maxPosition:o,minPosition:n,startPosition:e.message_position,limit:e.limit,direction:e.direction??g.up});if(r.length>0){const e=await this.httpClient.post("/message/get_by_position",{chat_position:{[i]:r}},{needSign:!1});if(e.ok&&e.data[i]){return b({has_more:d,list:this.appendXsid(e.data[i].reverse()),next_message_position:a})}}}return b({has_more:!1,list:[]})}createCustomMessage(e){if(null===this.context.loginUser)return m(u.SDK_ERROR,"not login");const t=this.feedCache.get(e.feed_id);if(null===t)return m(u.SDK_ERROR,"not found feed");const s=(new Date).toISOString();var i;return b({id:"",chat_id:t.chat_id,thread_id:t.thread_id,position:t.last_message_position,sender_id:this.context.loginUser.userId,message_kind_id:r.text,message_type_id:a.custom,send_at:s,edited_at:s,reader_ids:[],unreader_ids:[],hide_ids:[],operation:c.normal,operation_user_id:"0",content:(i={client_msg_id:e.client_msg_id,content:e.content},JSON.stringify({client_msg_id:i.client_msg_id,content:JSON.stringify(i.content)})),reactions:[]})}async sendMessageToFeed(e){if(e.message_type_id===a.custom){const t=y(e.content);return this.httpClient.post("/message/send_custom",{chat_id:e.chat_id,thread_id:e.thread_id,client_id:t.client_msg_id,content:null==t.content?void 0:JSON.stringify(t.content)})}return m(u.SDK_ERROR,"not support")}async sendMessageReadReceipt(e){const t=this.feedCache.get(e.feed_id);return null===t?m(u.SDK_ERROR,"not found feed"):await this.httpClient.post("/message/read",{chat_id:t.chat_id,message_ids:e.message_ids})}async joinRoom(e){return await this.httpClient.post("/liveshow/join",{room_id:e})}async setMute(e){const t=await this.httpClient.post("/feed/update",{id:e.feedId,is_mute:e.isMute?s.yes:s.no});return t.ok?t.data:null}async leaveRoom(e){return await this.httpClient.post("/liveshow/leave",{room_id:e})}async getJoinedRooms(){return await this.httpClient.get("/liveshow/joined_rooms")}async getRoomRecentMessageList(e){const t=await this.httpClient.get("/liveshow/get_recent_message",{room_id:e});return t.ok?b(t.data):t}async sendMessageToRoom(e){return await this.httpClient.post("/liveshow/send_message",{room_id:e.room_id,content:e.content})}}const W=new Map;function Y(e,t){let s=W.get(e);return void 0===s&&(s=new V(t),W.set(e,s)),s}const J={parseSystemMessageContent:e=>{const t=S(e);return null!==t?{text:t.text,text_i18n:t.text_i18n}:{}},parseTextMessageContent:e=>{const t=S(e);return null!==t?{text:t.text,client_msg_id:t.client_msg_id}:{}},parseCustomMessageContent:y};export{V as ChatSDK,Y as create,_ as enums,E as events,f as interfaces,J as utils};
package/dist/web-sdk.js CHANGED
@@ -1 +1 @@
1
- "use strict";var e,t,i,s,n,r,o,a,c=require("axios"),d=require("crypto-js");!function(e){e[e.yes=1]="yes",e[e.no=0]="no"}(e||(e={})),function(e){e[e.CREATE_FEED=0]="CREATE_FEED",e[e.UPDATE_FEED=1]="UPDATE_FEED",e[e.ADD_MESSAGE=2]="ADD_MESSAGE",e[e.UPDATE_MESSAGE=3]="UPDATE_MESSAGE",e[e.UPDATE_USER_DATA=4]="UPDATE_USER_DATA",e[e.USER_LOGIN=5]="USER_LOGIN",e[e.READ_MESSAGE=6]="READ_MESSAGE",e[e.PONG_MESSAGE=8]="PONG_MESSAGE",e[e.DELETE_MESSAGE=9]="DELETE_MESSAGE",e[e.UPDATE_GROUP=12]="UPDATE_GROUP",e[e.DELETE_GROUP=13]="DELETE_GROUP",e[e.UPDATE_LOGIN_USER=17]="UPDATE_LOGIN_USER",e[e.UPDATE_MESSAGE_REACTION=19]="UPDATE_MESSAGE_REACTION",e[e.ADD_GROUP_MEMBER=21]="ADD_GROUP_MEMBER",e[e.DEL_GROUP_MEMBER=22]="DEL_GROUP_MEMBER",e[e.ADD_CONTACTS=23]="ADD_CONTACTS",e[e.UPDATE_CONTACTS=24]="UPDATE_CONTACTS",e[e.DEL_CONTACTS=25]="DEL_CONTACTS",e[e.BLOCK_USER=26]="BLOCK_USER",e[e.DEVICE_CODE=27]="DEVICE_CODE",e[e.MSG_OPEN_CLOCK=28]="MSG_OPEN_CLOCK",e[e.DELETE_SECRET_CHAT=29]="DELETE_SECRET_CHAT",e[e.DELETE_FEED=30]="DELETE_FEED",e[e.FAVORITE_UPDATE=31]="FAVORITE_UPDATE",e[e.STICKERS_UPDATE=32]="STICKERS_UPDATE",e[e.CUSTOM_STICKERS_UPDATE=33]="CUSTOM_STICKERS_UPDATE",e[e.MANAGE_DEVICE_UPDATE=34]="MANAGE_DEVICE_UPDATE",e[e.MASS_MESSAGE_UPDATE=35]="MASS_MESSAGE_UPDATE",e[e.CHAT_WALLPAPER_DELETE=36]="CHAT_WALLPAPER_DELETE",e[e.CHAT_WALLPAPER_ADD=37]="CHAT_WALLPAPER_ADD",e[e.CONTACT_REQUEST=40]="CONTACT_REQUEST",e[e.USER_PREFERENCE_CHANGE=38]="USER_PREFERENCE_CHANGE",e[e.UPDATE_GROUP_PIN=41]="UPDATE_GROUP_PIN",e[e.RTC_CANCEL=46]="RTC_CANCEL",e[e.ADD_FEED_FOLDER=43]="ADD_FEED_FOLDER",e[e.UPDATE_FEED_FOLDER=44]="UPDATE_FEED_FOLDER",e[e.UPDATE_FOLDER_FEED_LIST=47]="UPDATE_FOLDER_FEED_LIST",e[e.DELETE_FEED_FOLDER=45]="DELETE_FEED_FOLDER",e[e.UPDATE_CHATTER=42]="UPDATE_CHATTER",e[e.PAPER_KEY=48]="PAPER_KEY",e[e.PAPER_KEY_LOG=49]="PAPER_KEY_LOG",e[e.USER_LOGIN_SCAN=50]="USER_LOGIN_SCAN",e[e.RTC_RINGING=51]="RTC_RINGING",e[e.ON_UPDATE_PRIVATE_SETTING=52]="ON_UPDATE_PRIVATE_SETTING",e[e.ON_DELETE_PRIVATE_SETTING=53]="ON_DELETE_PRIVATE_SETTING",e[e.ON_UPDATE_LOGIN_PRIVATE_SETTING=54]="ON_UPDATE_LOGIN_PRIVATE_SETTING",e[e.PUSH_LIVE_MESSAGE=56]="PUSH_LIVE_MESSAGE",e[e.PUSH_SYSTEM_NOTICE=58]="PUSH_SYSTEM_NOTICE",e[e.BIG_PACKAGE_PUSH=126]="BIG_PACKAGE_PUSH",e[e.KICK_OUT_DEVICE=127]="KICK_OUT_DEVICE",e[e.CLEAR_HISTORY=128]="CLEAR_HISTORY",e[e.CLEAR_DATA=255]="CLEAR_DATA"}(t||(t={})),function(e){e[e.singleChat=1]="singleChat",e[e.groupChat=2]="groupChat"}(i||(i={})),function(e){e[e.normal=0]="normal",e[e.thread=1]="thread"}(s||(s={})),function(e){e[e.text=0]="text",e[e.system=1]="system"}(n||(n={})),function(e){e[e.text=0]="text",e[e.image=1]="image",e[e.card=2]="card",e[e.audio=3]="audio",e[e.video=4]="video",e[e.file=5]="file",e[e.mergeForward=6]="mergeForward",e[e.sticker=7]="sticker",e[e.richText=8]="richText",e[e.custom=9]="custom"}(r||(r={})),function(e){e[e.Owner=1]="Owner",e[e.Admin=2]="Admin",e[e.Common=3]="Common",e[e.Bot=4]="Bot"}(o||(o={})),function(e){e[e.normal=0]="normal",e[e.recall=1]="recall",e[e.destroy=2]="destroy",e[e.edit=3]="edit",e[e.main_delete=4]="main_delete"}(a||(a={}));const l=["api-coco.typex.im","api-tx.typex-test.cn"];var h,_,u;!function(e){e.error="ERROR",e.warning="WARNING",e.info="INFO"}(h||(h={})),function(e){e[e.SDK_ERROR=-1e4]="SDK_ERROR",e[e.NETWORK_ERROR=-9999]="NETWORK_ERROR",e[e.MAKE_SIGN_FAIL=-9998]="MAKE_SIGN_FAIL",e[e.REQUEST_SINGLETON_LOCK_FAIL=-9997]="REQUEST_SINGLETON_LOCK_FAIL",e[e.SUCCESS=0]="SUCCESS"}(_||(_={})),function(e){e[e.up=0]="up",e[e.down=1]="down"}(u||(u={}));var g=Object.freeze({__proto__:null,get Bool(){return e},get ChatType(){return i},get FeedType(){return s},get GroupRole(){return o},get HttpClientResponseCode(){return _},get LogLevel(){return h},get MessageKind(){return n},get MessageOperation(){return a},get MessageType(){return r},get PushMessageType(){return t},RESOURCE_AUTH_DOMAINS:l,get RequestDirection(){return u}});const E={SDK_READY:"sdkReady",SDK_NOT_READY:"sdkNotReady",FEED_LIST_UPDATED:"feedListUpdated",MESSAGE_RECEIVED:"messageReceived",MESSAGE_RECALLED:"messageRecalled",MESSAGE_EDITED:"messageEdited",MESSAGE_DESTROYED:"messageDestroyed",MESSAGE_REACTION_UPDATED:"messageReactionUpdated",MESSAGE_RECEIPT_RECEIVED:"messageReceiptReceived",ROOM_MESSAGE_RECEIVED:"roomMessageReceived",SYSTEM_NOTICE_RECEIVED:"systemNoticeReceived"};var p=Object.freeze({__proto__:null,CHAT_SDK_EVENT:E}),m=Object.freeze({__proto__:null});function f(e,t){return{ok:!1,code:e,msg:t}}function b(e){return{ok:!0,data:e}}const S=e=>{try{return null==e||"string"!=typeof e||0===e.length?null:JSON.parse(e)}catch{return null}},C=e=>{const t=S(e);if(null!==t){let e;return null!=t.content&&(e=S(t.content)??void 0),{client_msg_id:t.client_msg_id,content:e}}return{}},T=e=>e.replace(/[.*+?^${}()|[\]\\]/g,"\\$&"),A=e=>new RegExp(`https?:\\\\?/\\\\?/${T(e)}(?:\\\\.|[^"\\\\\\s])*`,"g"),y=(e,t,i)=>{if(!e||"string"!=typeof e)return e;const s=A(t);return e.replace(s,e=>{const t=(e=>{try{return JSON.parse(`"${e}"`)}catch{return e}})(e),s=i(t);return"string"!=typeof s||s===t?e:(n=s,JSON.stringify(n).slice(1,-1));var n})};class R{constructor(e){Object.defineProperty(this,"all",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),this.all=e||new Map}on(e,t){const i=this.all.get(e);return i?i.push(t):this.all.set(e,[t]),()=>{this.off(e,t)}}off(e,t){const i=this.all.get(e);i&&(t?i.splice(i.indexOf(t)>>>0,1):this.all.set(e,[]))}emit(e,t){let i=this.all.get(e);i&&i.slice().map(e=>{e(t)}),i=this.all.get("*"),i&&i.slice().map(i=>{i(e,t)})}once(e,t){if("*"===e){const i=(e,s)=>{t(e,s),this.off("*",i)};this.on(e,i)}else{const i=s=>{t(s),this.off(e,i)};this.on(e,i)}}}class D extends R{constructor(e){super(),Object.defineProperty(this,"url",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"logger",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"ws",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"destroyed",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"pingTimeout",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"pongTimeout",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"reConnectTimeout",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),this.url=e.url,this.logger=e.logger,this.ws=null,this.destroyed=!1,this.pingTimeout=null,this.pongTimeout=null,this.reConnectTimeout=null,this.reConnect=this.reConnect.bind(this),window.addEventListener("online",this.reConnect),this.connect()}disconnect(){this.ws&&(this.ws.onopen=null,this.ws.onerror=null,this.ws.onmessage=null,this.ws.onclose=null,this.ws.close(),this.ws=null),null!==this.pingTimeout&&(clearTimeout(this.pingTimeout),this.pingTimeout=null),null!==this.pongTimeout&&(clearTimeout(this.pongTimeout),this.pongTimeout=null),null!==this.reConnectTimeout&&(clearTimeout(this.reConnectTimeout),this.reConnectTimeout=null)}connect(){if(this.ws)return void this.logger.warn("ReConnectWebsocket try connect but already connected");const e=new WebSocket(this.url);this.ws=e,e.onopen=()=>{this.delaySendPing()},e.onerror=e=>{this.logger.info("ReConnectWebsocket error",e)},e.onmessage=e=>{try{const i=JSON.parse(e.data);if(i.type===t.PONG_MESSAGE?null!==this.pongTimeout&&(clearTimeout(this.pongTimeout),this.pongTimeout=null,this.delaySendPing()):this.sendAck(i.id),i.type===t.BIG_PACKAGE_PUSH)for(const e of i.content.big_push)this.emit("message",e);else this.emit("message",i)}catch(e){this.logger.error("ReConnectWebsocket message parse failed",e)}},e.onclose=e=>{4001===e.code?this.kickOff():this.reConnect()}}reConnect(){this.disconnect(),this.destroyed||(this.reConnectTimeout=setTimeout(()=>{this.reConnectTimeout=null,this.connect()},5e3))}send(e){if(this.destroyed)return!1;if(!this.ws)return this.logger.warn("ReConnectWebsocket send before connect"),!1;try{return this.ws.readyState!==this.ws.OPEN?(this.logger.warn("ReConnectWebsocket send but not open",this.ws.readyState),!1):(this.ws.send(JSON.stringify(e)),!0)}catch(e){return this.logger.warn("ReConnectWebsocket send error",e),!1}}sendAck(e){this.send({type:1,ids:[e]})}destroy(){this.destroyed||(this.destroyed=!0,this.disconnect(),window.removeEventListener("online",this.reConnect))}delaySendPing(){null!==this.pingTimeout&&(clearTimeout(this.pingTimeout),this.pingTimeout=null),this.pingTimeout=setTimeout(()=>{this.pingTimeout=null;this.send({type:0})?this.waitPong():this.reConnect()},2e4)}waitPong(){this.pongTimeout=setTimeout(()=>{this.logger.info("ReConnectWebsocket pong timeout"),this.reConnect()},1e4)}kickOff(){this.destroy(),this.emit("kickoff")}}class v extends R{constructor(e){super(),Object.defineProperty(this,"host",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"context",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"logger",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"ws",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),this.host=e.host,this.context=e.context,this.logger=e.logger,this.ws=null}connect(){if(null===this.context.loginUser)return void this.logger.warn("BusinessWebsocket try connect but not login");if(this.ws)return void this.logger.warn("BusinessWebsocket try connect but already connected");const e=`${this.host}/ws?token=${this.context.loginUser.sessionId}&platform=web`;this.ws=new D({url:e,logger:this.logger}),this.ws.on("message",e=>{this.emit("message",e)}),this.ws.on("kickoff",()=>{this.emit("kickoff")})}disconnect(){this.ws?(this.ws.destroy(),this.ws=null):this.logger.info("BusinessWebsocket already disconnected")}}class w{constructor(){Object.defineProperty(this,"syncCompleted",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"map",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"chatMap",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"threadMap",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"targetMap",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"list",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"waitMap",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),this.syncCompleted=!1,this.map=new Map,this.chatMap=new Map,this.threadMap=new Map,this.targetMap=new Map,this.waitMap=new Map,this.list=[]}getAll(){const e=[];for(const t of this.list){const i=this.map.get(t);i&&e.push(i)}return e}get(e){return this.map.get(e)??null}getByChat(e,t){let i;return i=t&&"0"!==t?this.threadMap.get(t):this.chatMap.get(e),void 0!==i?this.get(i):null}getByTargetId(e){const t=this.targetMap.get(e);if(void 0===t)return[];const i=[];for(const e of t){const t=this.get(e);null!==t&&i.push(t)}return i}async waitFor(e){const t=this.get(e);if(t)return t;if(this.syncCompleted)return null;let i=this.waitMap.get(e);return i||(i=(()=>{let e=()=>{};return{promise:new Promise(t=>{e=t}),resolve:e}})(),this.waitMap.set(e,i)),await i.promise,this.get(e)}resolveWait(e){const t=this.waitMap.get(e);t&&(t.resolve(),this.waitMap.delete(e))}removeFromList(e){const t=this.list.indexOf(e);t>-1&&this.list.splice(t,1)}remove(e){const t=this.map.get(e);if(t){if(this.map.delete(e),t.feed_type===s.thread)this.threadMap.delete(t.thread_id);else if(this.chatMap.delete(t.chat_id),t.target_id&&"0"!==t.target_id){const e=this.targetMap.get(t.target_id);void 0!==e&&(e.delete(t.id),0===e.size&&this.targetMap.delete(t.target_id))}return this.removeFromList(e),!0}return!1}beforeSave(e){if(this.map.has(e.id))this.removeFromList(e.id);else if(e.feed_type===s.thread)this.threadMap.set(e.thread_id,e.id);else if(this.chatMap.set(e.chat_id,e.id),e.target_id&&"0"!==e.target_id){if(!this.targetMap.has(e.target_id)){const t=new Set;this.targetMap.set(e.target_id,t)}this.targetMap.get(e.target_id)?.add(e.id)}this.map.set(e.id,e)}afterSave(e){this.resolveWait(e.id)}push(e){this.beforeSave(e),this.list.push(e.id),this.afterSave(e)}unshift(e){this.beforeSave(e),this.list.unshift(e.id),this.afterSave(e)}update(e){this.map.has(e.id)&&this.map.set(e.id,e)}markSyncComplete(){this.syncCompleted=!0;for(const[e,t]of this.waitMap)t.resolve();this.waitMap.clear()}isSyncCompleted(){return this.syncCompleted}reset(){this.syncCompleted=!1,this.map.clear(),this.chatMap.clear(),this.threadMap.clear(),this.targetMap.clear(),this.waitMap.clear(),this.list=[]}}function P(e){return(new TextEncoder).encode(e).buffer}async function O(e,t){return window.crypto&&window.crypto.subtle?await async function(e,t){const i=P(t),s=P(e),n=await crypto.subtle.importKey("raw",i,{name:"HMAC",hash:{name:"SHA-256"}},!1,["sign"]),r=await crypto.subtle.sign("HMAC",n,s);return Array.from(new Uint8Array(r)).map(e=>e.toString(16).padStart(2,"0")).join("")}(e,t):function(e,t){return d.HmacSHA256(e,t).toString(d.enc.Hex)}(e,t)}const M=e=>{if(null==e)return"";if("object"!=typeof e||Array.isArray(e)){if(Array.isArray(e)){let t="";for(const i of e)t+=M(i);return t}return"string"==typeof e?e:String(e)}{const t=Object.keys(e).sort();let i="";for(const s of t)i+=M(e[s]);return i}};function L(){return f(_.MAKE_SIGN_FAIL,"make sign fail")}class U{constructor(e){Object.defineProperty(this,"api",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"context",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"logger",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),this.api=c.create({baseURL:e.host,headers:{"x-developer":e.developer},withCredentials:!0}),this.context=e.context,this.logger=e.logger}async request(e){try{const{needSign:t=!0,...i}=e;if(i.headers||(i.headers={}),i.headers.platform="web",t&&"POST"===e.method?.toUpperCase()&&i.data){if(null===this.context.loginUser)return this.logger.warn("HttpClient needs make sign but not login"),L();try{const e=await(async(e,t)=>{const i=await M(e);return await O(i,t)})(i.data,this.context.loginUser.secretKey);i.headers.sign=e}catch(e){return this.logger.error("HttpClient make sign error",e),L()}}this.context.loginUser&&(i.headers["X-Sid"]=this.context.loginUser.sessionId);const s=await this.api(i),n=s.data;return n.code===_.SUCCESS?{ok:!0,data:n.data}:(this.logger.info("HttpClient server error",s),{ok:!1,code:n.code,msg:n.msg,msg_i18n:n.msg_i18n})}catch{return{ok:!1,code:_.NETWORK_ERROR,msg:"network error"}}}get(e,t,i){return this.request({url:e,method:"GET",params:t,...i})}post(e,t,i){return this.request({url:e,method:"POST",data:t,...i})}}function I(e){return`${e}`.padStart(2,"0")}class k{constructor(){Object.defineProperty(this,"level",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"logHandler",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),this.level=h.error,this.logHandler=this.createLogHandler()}getPriority(e){switch(e){case h.error:return 3;case h.warning:return 2;case h.info:return 1;default:return 0}}createLogHandler(){return(e,...t)=>{const i=new Date,s=`TypeX >> [${`${i.getFullYear()}-${I(i.getMonth()+1)}-${I(i.getDate())} ${I(i.getHours())}:${I(i.getMinutes())}:${I(i.getSeconds())}.${i.getMilliseconds()}`}]`;switch(e){case h.error:console.error(s,"[ERR]",...t);break;case h.warning:console.warn(s,"[WARN]",...t);break;case h.info:console.info(s,"[INFO]",...t);break;default:console.log(s,...t)}}}log(e,...t){this.getPriority(e)>=this.getPriority(this.level)&&this.logHandler(e,...t)}setLogLevel(e){this.level=e,this.logHandler=this.createLogHandler()}info(...e){this.log(h.info,...e)}warn(...e){this.log(h.warning,...e)}error(...e){this.log(h.error,...e)}}class G{constructor(e){Object.defineProperty(this,"context",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"logger",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"emitter",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"feedCache",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"handleKickoff",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),this.context=e.context,this.logger=e.logger,this.emitter=e.emitter,this.feedCache=e.feedCache,this.handleKickoff=e.onKickoff}emitFeedListUpdated(){this.emitter.emit(E.FEED_LIST_UPDATED,{list:this.feedCache.getAll(),is_sync_completed:this.feedCache.isSyncCompleted()})}processCreateFeed(e){this.feedCache.unshift(e.content),this.emitFeedListUpdated()}processUpdateFeed(e){const t=e.content,i=this.feedCache.getByChat(t.chat_id,t.thread_id);if(null===i)return;const s={...i,...t};this.feedCache.update(s),this.emitFeedListUpdated()}processDeleteFeed(e){this.feedCache.remove(e.content.id)&&this.emitFeedListUpdated()}processAddMessage(t){if(null===this.context.loginUser)return;const i=this.context.loginUser.userId,s=t.content;if(s.hide_ids.includes(i))return;const r=this.feedCache.getByChat(s.chat_id,s.thread_id);if(null!==r){if(s.no_last_msg!==e.yes){let t=!1,o=!1;const a={};if(s.message_kind_id!==n.system&&s.sender_id!==i&&s.no_read!==e.yes){t=!0;const e=new Set(r.unread_message_ids);e.add(s.id),a.unread_message_ids=[...e],a.badge=e.size}if(r.last_message_position<s.position&&(t=!0,o=!0,a.last_message_id=s.id,a.last_message_position=s.position,a.last_message_sender_id=s.sender_id,a.last_message_send_at=s.send_at,a.last_message_kind_id=s.message_kind_id,a.last_message_type_id=s.message_type_id,a.last_message=s.content,a.last_message_operation=s.operation,a.last_message_operation_user_id=s.operation_user_id),t){const e={...r,...a};o?this.feedCache.unshift(e):this.feedCache.update(e),this.emitFeedListUpdated()}}this.emitter.emit(E.MESSAGE_RECEIVED,{feed_id:r.id,message:s})}}processUpdateMessage(e){const t=e.content,i=this.feedCache.getByChat(t.chat_id,t.thread_id);if(null!==i&&null!=t.operation){let e=!1;const s={};if(t.operation===a.recall||t.operation===a.destroy){if(null!=i.unread_message_ids&&i.unread_message_ids.includes(t.id)){e=!0;const n=new Set(i.unread_message_ids);n.delete(t.id),s.unread_message_ids=[...n],s.badge=s.unread_message_ids.length}i.last_message_id===t.id&&(e=!0,s.last_message=t.content??"{}",s.last_message_operation=t.operation,s.last_message_operation_user_id=t.operation_user_id??"0")}else t.operation===a.edit&&i.last_message_id===t.id&&(e=!0,s.last_message_kind_id=t.message_kind_id,s.last_message_type_id=t.message_type_id,s.last_message=t.content,s.last_message_operation=t.operation,s.last_message_operation_user_id=t.operation_user_id);e&&(this.feedCache.update({...i,...s}),this.emitFeedListUpdated()),t.operation===a.recall?this.emitter.emit(E.MESSAGE_RECALLED,{message_ids:[t.id]}):t.operation===a.edit?null!=t.content&&null!=t.edited_at&&null!=t.message_kind_id&&null!=t.message_type_id&&null!=t.operation_user_id&&this.emitter.emit(E.MESSAGE_EDITED,{chat_id:t.chat_id,content:t.content,edited_at:t.edited_at,id:t.id,message_kind_id:t.message_kind_id,message_type_id:t.message_type_id,operation:t.operation,operation_user_id:t.operation_user_id,thread_id:t.thread_id}):t.operation===a.destroy&&this.emitter.emit(E.MESSAGE_DESTROYED,{feed_id:i.id,message_ids:[t.id]})}}processPushLiveMessage(e){this.emitter.emit(E.ROOM_MESSAGE_RECEIVED,{room_id:e.content.room_id,content:e.content.message})}processPushSystemNotice(e){this.emitter.emit(E.SYSTEM_NOTICE_RECEIVED,{content:e.content})}processReadMessage(e){if(null===this.context.loginUser)return;const t=this.context.loginUser.userId,i=e.content,s=this.feedCache.getByChat(i.chat_id,i.thread_id);if(null===s)return;let n=!1;const r={};if(i.reader_ids.includes(t)&&i.message_ids.length>0){n=!0;const e=new Set(s.unread_message_ids);i.message_ids.forEach(t=>{e.delete(t)}),r.unread_message_ids=[...e],r.badge=e.size}n&&(this.feedCache.update({...s,...r}),this.emitFeedListUpdated()),this.emitter.emit(E.MESSAGE_RECEIPT_RECEIVED,{feed_id:s.id,message_ids:i.message_ids,reader_user_ids:i.reader_ids})}processKickOutDevice(){this.handleKickoff()}processGroupMember(e){const i=e.content,s=this.feedCache.getByChat(i.chat_id,"0");if(null===s)return;const n=new Set(s.chat_member),r=e.type===t.ADD_GROUP_MEMBER,o=e.type===t.DEL_GROUP_MEMBER;i.chat_member.forEach(e=>{r?n.add(e.chat_id):o&&n.delete(e.chat_id)}),this.feedCache.update({...s,chat_member:[...n]}),this.emitFeedListUpdated()}processUpdateGroup(e){const t=e.content,i=this.feedCache.getByChat(t.chat_id,"0");if(null===i)return;let s=!1;const n={};null!=t.avatar&&(s=!0,n.avatar=t.avatar),null!=t.name&&(s=!0,n.name=t.name),s&&(this.feedCache.update({...i,...n}),this.emitFeedListUpdated())}processUpdateUserData(e){const t=e.content,i=this.feedCache.getByTargetId(t.id);if(i.length>0){const e={};if(null!=t.avatar&&(e.avatar=t.avatar),null!=t.first_name||null!=t.last_name){let i=t.first_name??"";null!=t.last_name&&(i=i.length>0?`${i} ${t.last_name}`:t.last_name),e.name=i}for(const t of i)this.feedCache.update({...t,...e});this.emitFeedListUpdated()}}processUpdateMessageReaction(e){const t=e.content,i=this.feedCache.getByChat(t.chat_id,t.thread_id);null!==i&&this.emitter.emit(E.MESSAGE_REACTION_UPDATED,{feed_id:i.id,message_id:t.message_id,reactions:t.reactions})}process(e){switch(this.logger.info("PushMessageProcessor process",e),e.type){case t.CREATE_FEED:this.processCreateFeed(e);break;case t.UPDATE_FEED:this.processUpdateFeed(e);break;case t.DELETE_FEED:this.processDeleteFeed(e);break;case t.ADD_MESSAGE:this.processAddMessage(e);break;case t.UPDATE_MESSAGE:this.processUpdateMessage(e);break;case t.PUSH_LIVE_MESSAGE:this.processPushLiveMessage(e);break;case t.PUSH_SYSTEM_NOTICE:this.processPushSystemNotice(e);break;case t.READ_MESSAGE:this.processReadMessage(e);break;case t.KICK_OUT_DEVICE:this.processKickOutDevice();break;case t.ADD_GROUP_MEMBER:case t.DEL_GROUP_MEMBER:this.processGroupMember(e);break;case t.UPDATE_GROUP:this.processUpdateGroup(e);break;case t.UPDATE_USER_DATA:this.processUpdateUserData(e);break;case t.UPDATE_MESSAGE_REACTION:this.processUpdateMessageReaction(e)}}}class x{constructor(){Object.defineProperty(this,"obtained",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"abortLockObtain",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),this.obtained=!1,this.abortLockObtain=null}async requestLock(){if(this.obtained)return!0;let e=()=>{};const t=new Promise(t=>{e=t}),i=new Promise(e=>{this.abortLockObtain=e});navigator.locks.request("typex-sdk",{ifAvailable:!0},async t=>{t?(this.obtained=!0,e(!0),await i):e(!1)});return await t}releaseLock(){this.obtained=!1,null!==this.abortLockObtain&&(this.abortLockObtain(),this.abortLockObtain=null)}}class N{static set(e){localStorage.setItem(this.key,JSON.stringify(e))}static get(){try{const e=localStorage.getItem(this.key);if(!e)return null;return JSON.parse(e)}catch{return null}}static clear(){localStorage.removeItem(this.key)}}Object.defineProperty(N,"key",{enumerable:!0,configurable:!0,writable:!0,value:"__typex_sdk_data__"});class F{constructor(){Object.defineProperty(this,"version",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),this.version=0}increment(){this.version++}get(){return this.version}check(e){return e===this.version}}class K extends R{constructor(e){super(),Object.defineProperty(this,"context",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"version",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"singletonLock",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"logger",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"httpClient",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"feedCache",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"ws",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"pushMessageProcessor",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),this.context={isLogin:!1,loginUser:null,isReady:!1,deviceId:null},this.version=new F,this.singletonLock=new x,this.logger=new k,this.httpClient=new U({host:e.httpHost,context:this.context,logger:this.logger,developer:e.developer}),this.feedCache=new w,this.ws=new v({host:e.websocketHost,context:this.context,logger:this.logger}),this.pushMessageProcessor=new G({context:this.context,logger:this.logger,emitter:this,feedCache:this.feedCache,onKickoff:()=>{this.afterLogout()}}),this.init()}init(){this.loadContext(),this.ws.on("message",e=>{this.pushMessageProcessor.process(e)}),this.ws.on("kickoff",()=>{this.afterLogout()})}async requestDeviceId(){if(this.context.deviceId)return!0;const e=await this.httpClient.post("/device_api/device_id",{platform:"web",hash_str:""},{needSign:!1});return!!e.ok&&(this.context.deviceId=e.data,this.saveContext(),!0)}saveContext(){const{context:e}=this;N.set({deviceId:e.deviceId})}loadContext(){const e=N.get();e&&e.deviceId&&(this.context.deviceId=e.deviceId)}applyLoginStatus(){this.version.increment(),this.saveContext(),this.context.isLogin?(this.ws.connect(),this.loadFeedList(),this.context.isReady=!0,this.emit(E.SDK_READY)):(this.ws.disconnect(),this.feedCache.reset(),this.singletonLock.releaseLock(),this.context.isReady=!1,this.emit(E.SDK_NOT_READY))}async loadFeedList(){const e=this.version.get(),t={refresh_at:null,feed_id:null};for(;;){const i=await this.httpClient.get("/feed",{limit:500,last_refresh_at:t.refresh_at??void 0,last_feed_id:t.feed_id??void 0});if(!this.version.check(e))break;if(!i.ok||null===i.data)break;if(t.refresh_at=i.data.refresh_at,t.feed_id=i.data.last_feed_id,(i.data.feed_list??[]).forEach(e=>{this.feedCache.push(e)}),!i.data.has_more)break}this.version.check(e)&&(this.feedCache.markSyncComplete(),this.emit(E.FEED_LIST_UPDATED,{list:this.feedCache.getAll(),is_sync_completed:!0}))}isReady(){return this.context.isReady}setLogLevel(e){this.logger.setLogLevel(e)}async login(e){if(this.context.isLogin)return b(null);if(!await this.singletonLock.requestLock())return this.logger.error("Another active TypeX SDK instance detected"),f(_.REQUEST_SINGLETON_LOCK_FAIL,"Another active TypeX SDK instance detected");if(await this.requestDeviceId(),!this.context.deviceId)return this.logger.error("Get deviceId failed"),f(_.SDK_ERROR,"Get deviceId failed");const t=await this.httpClient.post("/user/session/login",{userCode:e.user_code,device_id:this.context.deviceId},{needSign:!1});return t.ok?(this.context.isLogin=!0,this.context.loginUser={userId:t.data.id,secretKey:t.data.key,sessionId:e.user_code},this.applyLoginStatus(),b(null)):(this.singletonLock.releaseLock(),t)}async logout(){if(!this.context.isLogin)return b(null);const e=await this.httpClient.get("/user/logout");return e.ok?(this.afterLogout(),b(null)):e}async afterLogout(){this.context.isLogin=!1,this.context.loginUser=null,this.applyLoginStatus()}getLoginUser(){return null===this.context.loginUser?null:this.context.loginUser.userId}async createSingleChatFeed(e){return await this.httpClient.post("/chat/single",{receiver_id:e})}async deleteFeed(e){return await this.httpClient.post("/feed/delete",{feed_id_list:[e],delete_peer:!0})}async getFeedList(){return b({list:this.feedCache.getAll(),is_sync_completed:this.feedCache.isSyncCompleted()})}async getFeedDetail(e){return b(await this.feedCache.waitFor(e))}async getFeedMemberList(e){const t=await this.feedCache.get(e);return null!==t&&t.chat_member.length>0?await this.httpClient.post("/chat/chatter_info",{chatters:{[t.chat_id]:t.chat_member}}):b([])}getDomain(e){const[t,i]=l,s=A(t),n=A(i);for(const r of e){if(s.test(r.content))return t;if(n.test(r.content))return i}}appendXsid(e){if(!this.context.loginUser?.sessionId)return e;const t=this.context.loginUser.sessionId,i=this.getDomain(e);return i?e.map(e=>{const s=y(e.content,i,e=>((e,t,i)=>{const s=encodeURIComponent(t),n=encodeURIComponent(i),r=e.indexOf("#"),o=r>=0?e.slice(0,r):e,a=r>=0?e.slice(r):"",c=new RegExp(`([?&])${T(s)}=[^&#]*`);if(c.test(o))return o.replace(c,`$1${s}=${n}`)+a;const d=o.includes("?")?"&":"?";return`${o}${d}${s}=${n}${a}`})(e,"xsid",t));return{...e,content:s}}):e}async markFeedMessageAsRead(t){const i=this.feedCache.get(t);if(!i)return b(!1);if(!(await this.httpClient.post("/feed/update",{id:i.id,mark_unread:e.yes})).ok)return b(!1);return(await this.httpClient.post("/message/read",{chat_id:i.chat_id,thread_id:i.thread_id})).ok?b(!0):b(!1)}async getMessagesByIds(e,t){const i=this.feedCache.get(e);if(!i||!Array.isArray(t)||0===t.length)return b([]);const s=await this.httpClient.post("/message/get_by_msgid",{chat_msg_id_map:{[i.chat_id]:t}});if(s.ok){return b(this.appendXsid(s.data[i.chat_id]))}return b([])}async getFeedMessageList(e){const t=await this.getFeedDetail(e.feed_id);if(t.ok&&t.data){const i=t.data,{chat_id:s,first_position:n,last_message_position:r}=i,{positions:o,nextPosition:a,hasMore:c}=(e=>{const t=[];if(e.direction===u.up){let i=e.startPosition??e.maxPosition;for(;t.length<e.limit&&i>=e.minPosition;)t.push(i),i--;const s=i>=e.minPosition;let n;return s&&(n=i),{positions:t,nextPosition:n,hasMore:s}}{let i=e.startPosition??e.minPosition;for(;t.length<e.limit&&i<=e.maxPosition;)t.push(i),i++;const s=i<=e.maxPosition;let n;return s&&(n=i),{positions:t,nextPosition:n,hasMore:s}}})({maxPosition:r,minPosition:n,startPosition:e.message_position,limit:e.limit,direction:e.direction??u.up});if(o.length>0){const e=await this.httpClient.post("/message/get_by_position",{chat_position:{[s]:o}},{needSign:!1});if(e.ok&&e.data[s]){return b({has_more:c,list:this.appendXsid(e.data[s].reverse()),next_message_position:a})}}}return b({has_more:!1,list:[]})}createCustomMessage(e){if(null===this.context.loginUser)return f(_.SDK_ERROR,"not login");const t=this.feedCache.get(e.feed_id);if(null===t)return f(_.SDK_ERROR,"not found feed");const i=(new Date).toISOString();var s;return b({id:"",chat_id:t.chat_id,thread_id:t.thread_id,position:t.last_message_position,sender_id:this.context.loginUser.userId,message_kind_id:n.text,message_type_id:r.custom,send_at:i,edited_at:i,reader_ids:[],unreader_ids:[],hide_ids:[],operation:a.normal,operation_user_id:"0",content:(s={client_msg_id:e.client_msg_id,content:e.content},JSON.stringify({client_msg_id:s.client_msg_id,content:JSON.stringify(s.content)})),reactions:[]})}async sendMessageToFeed(e){if(e.message_type_id===r.custom){const t=C(e.content);return this.httpClient.post("/message/send_custom",{chat_id:e.chat_id,thread_id:e.thread_id,client_id:t.client_msg_id,content:null==t.content?void 0:JSON.stringify(t.content)})}return f(_.SDK_ERROR,"not support")}async sendMessageReadReceipt(e){const t=this.feedCache.get(e.feed_id);return null===t?f(_.SDK_ERROR,"not found feed"):await this.httpClient.post("/message/read",{chat_id:t.chat_id,message_ids:e.message_ids})}async joinRoom(e){return await this.httpClient.post("/liveshow/join",{room_id:e})}async setMute(t){const i=await this.httpClient.post("/feed/update",{id:t.feedId,is_mute:t.isMute?e.yes:e.no});return i.ok?i.data:null}async leaveRoom(e){return await this.httpClient.post("/liveshow/leave",{room_id:e})}async getRoomRecentMessageList(e){const t=await this.httpClient.get("/liveshow/get_recent_message",{room_id:e});return t.ok?b(t.data):t}async sendMessageToRoom(e){return await this.httpClient.post("/liveshow/send_message",{room_id:e.room_id,content:e.content})}}const j=new Map;const H={parseSystemMessageContent:e=>{const t=S(e);return null!==t?{text:t.text,text_i18n:t.text_i18n}:{}},parseTextMessageContent:e=>{const t=S(e);return null!==t?{text:t.text,client_msg_id:t.client_msg_id}:{}},parseCustomMessageContent:C};exports.ChatSDK=K,exports.create=function(e,t){let i=j.get(e);return void 0===i&&(i=new K(t),j.set(e,i)),i},exports.enums=g,exports.events=p,exports.interfaces=m,exports.utils=H;
1
+ "use strict";var e,t,s,i,n,r,o,a,d=require("axios"),c=require("crypto-js");!function(e){e[e.yes=1]="yes",e[e.no=0]="no"}(e||(e={})),function(e){e[e.CREATE_FEED=0]="CREATE_FEED",e[e.UPDATE_FEED=1]="UPDATE_FEED",e[e.ADD_MESSAGE=2]="ADD_MESSAGE",e[e.UPDATE_MESSAGE=3]="UPDATE_MESSAGE",e[e.UPDATE_USER_DATA=4]="UPDATE_USER_DATA",e[e.USER_LOGIN=5]="USER_LOGIN",e[e.READ_MESSAGE=6]="READ_MESSAGE",e[e.PONG_MESSAGE=8]="PONG_MESSAGE",e[e.DELETE_MESSAGE=9]="DELETE_MESSAGE",e[e.UPDATE_GROUP=12]="UPDATE_GROUP",e[e.DELETE_GROUP=13]="DELETE_GROUP",e[e.UPDATE_LOGIN_USER=17]="UPDATE_LOGIN_USER",e[e.UPDATE_MESSAGE_REACTION=19]="UPDATE_MESSAGE_REACTION",e[e.ADD_GROUP_MEMBER=21]="ADD_GROUP_MEMBER",e[e.DEL_GROUP_MEMBER=22]="DEL_GROUP_MEMBER",e[e.ADD_CONTACTS=23]="ADD_CONTACTS",e[e.UPDATE_CONTACTS=24]="UPDATE_CONTACTS",e[e.DEL_CONTACTS=25]="DEL_CONTACTS",e[e.BLOCK_USER=26]="BLOCK_USER",e[e.DEVICE_CODE=27]="DEVICE_CODE",e[e.MSG_OPEN_CLOCK=28]="MSG_OPEN_CLOCK",e[e.DELETE_SECRET_CHAT=29]="DELETE_SECRET_CHAT",e[e.DELETE_FEED=30]="DELETE_FEED",e[e.FAVORITE_UPDATE=31]="FAVORITE_UPDATE",e[e.STICKERS_UPDATE=32]="STICKERS_UPDATE",e[e.CUSTOM_STICKERS_UPDATE=33]="CUSTOM_STICKERS_UPDATE",e[e.MANAGE_DEVICE_UPDATE=34]="MANAGE_DEVICE_UPDATE",e[e.MASS_MESSAGE_UPDATE=35]="MASS_MESSAGE_UPDATE",e[e.CHAT_WALLPAPER_DELETE=36]="CHAT_WALLPAPER_DELETE",e[e.CHAT_WALLPAPER_ADD=37]="CHAT_WALLPAPER_ADD",e[e.CONTACT_REQUEST=40]="CONTACT_REQUEST",e[e.USER_PREFERENCE_CHANGE=38]="USER_PREFERENCE_CHANGE",e[e.UPDATE_GROUP_PIN=41]="UPDATE_GROUP_PIN",e[e.RTC_CANCEL=46]="RTC_CANCEL",e[e.ADD_FEED_FOLDER=43]="ADD_FEED_FOLDER",e[e.UPDATE_FEED_FOLDER=44]="UPDATE_FEED_FOLDER",e[e.UPDATE_FOLDER_FEED_LIST=47]="UPDATE_FOLDER_FEED_LIST",e[e.DELETE_FEED_FOLDER=45]="DELETE_FEED_FOLDER",e[e.UPDATE_CHATTER=42]="UPDATE_CHATTER",e[e.PAPER_KEY=48]="PAPER_KEY",e[e.PAPER_KEY_LOG=49]="PAPER_KEY_LOG",e[e.USER_LOGIN_SCAN=50]="USER_LOGIN_SCAN",e[e.RTC_RINGING=51]="RTC_RINGING",e[e.ON_UPDATE_PRIVATE_SETTING=52]="ON_UPDATE_PRIVATE_SETTING",e[e.ON_DELETE_PRIVATE_SETTING=53]="ON_DELETE_PRIVATE_SETTING",e[e.ON_UPDATE_LOGIN_PRIVATE_SETTING=54]="ON_UPDATE_LOGIN_PRIVATE_SETTING",e[e.PUSH_LIVE_MESSAGE=56]="PUSH_LIVE_MESSAGE",e[e.PUSH_SYSTEM_NOTICE=58]="PUSH_SYSTEM_NOTICE",e[e.BIG_PACKAGE_PUSH=126]="BIG_PACKAGE_PUSH",e[e.KICK_OUT_DEVICE=127]="KICK_OUT_DEVICE",e[e.CLEAR_HISTORY=128]="CLEAR_HISTORY",e[e.CLEAR_DATA=255]="CLEAR_DATA"}(t||(t={})),function(e){e[e.singleChat=1]="singleChat",e[e.groupChat=2]="groupChat"}(s||(s={})),function(e){e[e.normal=0]="normal",e[e.thread=1]="thread"}(i||(i={})),function(e){e[e.text=0]="text",e[e.system=1]="system"}(n||(n={})),function(e){e[e.text=0]="text",e[e.image=1]="image",e[e.card=2]="card",e[e.audio=3]="audio",e[e.video=4]="video",e[e.file=5]="file",e[e.mergeForward=6]="mergeForward",e[e.sticker=7]="sticker",e[e.richText=8]="richText",e[e.custom=9]="custom"}(r||(r={})),function(e){e[e.Owner=1]="Owner",e[e.Admin=2]="Admin",e[e.Common=3]="Common",e[e.Bot=4]="Bot"}(o||(o={})),function(e){e[e.normal=0]="normal",e[e.recall=1]="recall",e[e.destroy=2]="destroy",e[e.edit=3]="edit",e[e.main_delete=4]="main_delete"}(a||(a={}));const l=["api-coco.typex.im","api-tx.typex-test.cn"];var h,u,g;!function(e){e.error="ERROR",e.warning="WARNING",e.info="INFO"}(h||(h={})),function(e){e[e.SDK_ERROR=-1e4]="SDK_ERROR",e[e.NETWORK_ERROR=-9999]="NETWORK_ERROR",e[e.MAKE_SIGN_FAIL=-9998]="MAKE_SIGN_FAIL",e[e.REQUEST_SINGLETON_LOCK_FAIL=-9997]="REQUEST_SINGLETON_LOCK_FAIL",e[e.SUCCESS=0]="SUCCESS"}(u||(u={})),function(e){e[e.up=0]="up",e[e.down=1]="down"}(g||(g={}));var _=Object.freeze({__proto__:null,get Bool(){return e},get ChatType(){return s},get FeedType(){return i},get GroupRole(){return o},get HttpClientResponseCode(){return u},get LogLevel(){return h},get MessageKind(){return n},get MessageOperation(){return a},get MessageType(){return r},get PushMessageType(){return t},RESOURCE_AUTH_DOMAINS:l,get RequestDirection(){return g}});const p={SDK_READY:"sdkReady",SDK_NOT_READY:"sdkNotReady",FEED_LIST_UPDATED:"feedListUpdated",MESSAGE_RECEIVED:"messageReceived",MESSAGE_RECALLED:"messageRecalled",MESSAGE_EDITED:"messageEdited",MESSAGE_DESTROYED:"messageDestroyed",MESSAGE_REACTION_UPDATED:"messageReactionUpdated",MESSAGE_RECEIPT_RECEIVED:"messageReceiptReceived",MESSAGE_OPEN_CLOCK:"messageOpenClock",ROOM_MESSAGE_RECEIVED:"roomMessageReceived",SYSTEM_NOTICE_RECEIVED:"systemNoticeReceived"};var E=Object.freeze({__proto__:null,CHAT_SDK_EVENT:p}),f=Object.freeze({__proto__:null});function m(e,t){return{ok:!1,code:e,msg:t}}function b(e){return{ok:!0,data:e}}const S=e=>{try{return null==e||"string"!=typeof e||0===e.length?null:JSON.parse(e)}catch{return null}},y=e=>{const t=S(e);if(null!==t){let e;return null!=t.content&&(e=S(t.content)??void 0),{client_msg_id:t.client_msg_id,content:e}}return{}},C=e=>e.replace(/[.*+?^${}()|[\]\\]/g,"\\$&"),T=e=>new RegExp(`https?:\\\\?/\\\\?/${C(e)}(?:\\\\.|[^"\\\\\\s])*`,"g"),v=(e,t,s)=>{if(!e||"string"!=typeof e)return e;const i=T(t);return e.replace(i,e=>{const t=(e=>{try{return JSON.parse(`"${e}"`)}catch{return e}})(e),i=s(t);return"string"!=typeof i||i===t?e:(n=i,JSON.stringify(n).slice(1,-1));var n})};class w{constructor(e){Object.defineProperty(this,"all",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),this.all=e||new Map}on(e,t){const s=this.all.get(e);return s?s.push(t):this.all.set(e,[t]),()=>{this.off(e,t)}}off(e,t){const s=this.all.get(e);s&&(t?s.splice(s.indexOf(t)>>>0,1):this.all.set(e,[]))}emit(e,t){let s=this.all.get(e);s&&s.slice().map(e=>{e(t)}),s=this.all.get("*"),s&&s.slice().map(s=>{s(e,t)})}once(e,t){if("*"===e){const s=(e,i)=>{t(e,i),this.off("*",s)};this.on(e,s)}else{const s=i=>{t(i),this.off(e,s)};this.on(e,s)}}}function A(e){const t=(new TextEncoder).encode(e);let s="";for(const e of t)s+=String.fromCharCode(e);return btoa(s).replace(/\+/g,"-").replace(/\//g,"_").replace(/=+$/,"")}class R extends w{constructor(e){super(),Object.defineProperty(this,"url",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"token",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"logger",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"ws",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"destroyed",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"pingTimeout",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"pongTimeout",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"reConnectTimeout",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),this.url=e.url,this.token=e.token,this.logger=e.logger,this.ws=null,this.destroyed=!1,this.pingTimeout=null,this.pongTimeout=null,this.reConnectTimeout=null,this.reConnect=this.reConnect.bind(this),window.addEventListener("online",this.reConnect),this.connect()}disconnect(){this.ws&&(this.ws.onopen=null,this.ws.onerror=null,this.ws.onmessage=null,this.ws.onclose=null,this.ws.close(),this.ws=null),null!==this.pingTimeout&&(clearTimeout(this.pingTimeout),this.pingTimeout=null),null!==this.pongTimeout&&(clearTimeout(this.pongTimeout),this.pongTimeout=null),null!==this.reConnectTimeout&&(clearTimeout(this.reConnectTimeout),this.reConnectTimeout=null)}connect(){if(this.ws)return void this.logger.warn("ReConnectWebsocket try connect but already connected");const e=new URL(this.url);e.searchParams.set("platform","web");const s=new WebSocket(e.toString(),["typex.im.auth.v1",`typex.im.auth.b64url.${A(this.token)}`]);this.ws=s,s.onopen=()=>{this.delaySendPing()},s.onerror=e=>{this.logger.info("ReConnectWebsocket error",e)},s.onmessage=e=>{try{const s=JSON.parse(e.data);if(s.type===t.PONG_MESSAGE?null!==this.pongTimeout&&(clearTimeout(this.pongTimeout),this.pongTimeout=null,this.delaySendPing()):this.sendAck(s.id),s.type===t.BIG_PACKAGE_PUSH)for(const e of s.content.big_push)this.emit("message",e);else this.emit("message",s)}catch(e){this.logger.error("ReConnectWebsocket message parse failed",e)}},s.onclose=e=>{4001===e.code?this.kickOff():this.reConnect()}}reConnect(){this.disconnect(),this.destroyed||(this.reConnectTimeout=setTimeout(()=>{this.reConnectTimeout=null,this.connect()},5e3))}send(e){if(this.destroyed)return!1;if(!this.ws)return this.logger.warn("ReConnectWebsocket send before connect"),!1;try{return this.ws.readyState!==this.ws.OPEN?(this.logger.warn("ReConnectWebsocket send but not open",this.ws.readyState),!1):(this.ws.send(JSON.stringify(e)),!0)}catch(e){return this.logger.warn("ReConnectWebsocket send error",e),!1}}sendAck(e){this.send({type:1,ids:[e]})}destroy(){this.destroyed||(this.destroyed=!0,this.disconnect(),window.removeEventListener("online",this.reConnect))}delaySendPing(){null!==this.pingTimeout&&(clearTimeout(this.pingTimeout),this.pingTimeout=null),this.pingTimeout=setTimeout(()=>{this.pingTimeout=null;this.send({type:0})?this.waitPong():this.reConnect()},2e4)}waitPong(){this.pongTimeout=setTimeout(()=>{this.logger.info("ReConnectWebsocket pong timeout"),this.reConnect()},1e4)}kickOff(){this.destroy(),this.emit("kickoff")}}class O extends w{constructor(e){super(),Object.defineProperty(this,"host",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"context",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"logger",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"ws",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),this.host=e.host,this.context=e.context,this.logger=e.logger,this.ws=null}connect(){null!==this.context.loginUser?this.ws?this.logger.warn("BusinessWebsocket try connect but already connected"):(this.ws=new R({url:`${this.host}/ws`,token:this.context.loginUser.sessionId,logger:this.logger}),this.ws.on("message",e=>{this.emit("message",e)}),this.ws.on("kickoff",()=>{this.emit("kickoff")})):this.logger.warn("BusinessWebsocket try connect but not login")}disconnect(){this.ws?(this.ws.destroy(),this.ws=null):this.logger.info("BusinessWebsocket already disconnected")}}class D{constructor(){Object.defineProperty(this,"syncCompleted",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"map",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"chatMap",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"threadMap",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"targetMap",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"list",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"waitMap",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),this.syncCompleted=!1,this.map=new Map,this.chatMap=new Map,this.threadMap=new Map,this.targetMap=new Map,this.waitMap=new Map,this.list=[]}getAll(){const e=[];for(const t of this.list){const s=this.map.get(t);s&&e.push(s)}return e}get(e){return this.map.get(e)??null}getByChat(e,t){let s;return s=t&&"0"!==t?this.threadMap.get(t):this.chatMap.get(e),void 0!==s?this.get(s):null}getByTargetId(e){const t=this.targetMap.get(e);if(void 0===t)return[];const s=[];for(const e of t){const t=this.get(e);null!==t&&s.push(t)}return s}async waitFor(e){const t=this.get(e);if(t)return t;if(this.syncCompleted)return null;let s=this.waitMap.get(e);return s||(s=(()=>{let e=()=>{};return{promise:new Promise(t=>{e=t}),resolve:e}})(),this.waitMap.set(e,s)),await s.promise,this.get(e)}resolveWait(e){const t=this.waitMap.get(e);t&&(t.resolve(),this.waitMap.delete(e))}removeFromList(e){const t=this.list.indexOf(e);t>-1&&this.list.splice(t,1)}remove(e){const t=this.map.get(e);if(t){if(this.map.delete(e),t.feed_type===i.thread)this.threadMap.delete(t.thread_id);else if(this.chatMap.delete(t.chat_id),t.target_id&&"0"!==t.target_id){const e=this.targetMap.get(t.target_id);void 0!==e&&(e.delete(t.id),0===e.size&&this.targetMap.delete(t.target_id))}return this.removeFromList(e),!0}return!1}beforeSave(e){if(this.map.has(e.id))this.removeFromList(e.id);else if(e.feed_type===i.thread)this.threadMap.set(e.thread_id,e.id);else if(this.chatMap.set(e.chat_id,e.id),e.target_id&&"0"!==e.target_id){if(!this.targetMap.has(e.target_id)){const t=new Set;this.targetMap.set(e.target_id,t)}this.targetMap.get(e.target_id)?.add(e.id)}this.map.set(e.id,e)}afterSave(e){this.resolveWait(e.id)}push(e){this.beforeSave(e),this.list.push(e.id),this.afterSave(e)}unshift(e){this.beforeSave(e),this.list.unshift(e.id),this.afterSave(e)}update(e){this.map.has(e.id)&&this.map.set(e.id,e)}markSyncComplete(){this.syncCompleted=!0;for(const[e,t]of this.waitMap)t.resolve();this.waitMap.clear()}isSyncCompleted(){return this.syncCompleted}reset(){this.syncCompleted=!1,this.map.clear(),this.chatMap.clear(),this.threadMap.clear(),this.targetMap.clear(),this.waitMap.clear(),this.list=[]}}function P(e){return(new TextEncoder).encode(e).buffer}async function L(e,t){return window.crypto&&window.crypto.subtle?await async function(e,t){const s=P(t),i=P(e),n=await crypto.subtle.importKey("raw",s,{name:"HMAC",hash:{name:"SHA-256"}},!1,["sign"]),r=await crypto.subtle.sign("HMAC",n,i);return Array.from(new Uint8Array(r)).map(e=>e.toString(16).padStart(2,"0")).join("")}(e,t):function(e,t){return c.HmacSHA256(e,t).toString(c.enc.Hex)}(e,t)}const M=e=>{if(null==e)return"";if("object"!=typeof e||Array.isArray(e)){if(Array.isArray(e)){let t="";for(const s of e)t+=M(s);return t}return"string"==typeof e?e:String(e)}{const t=Object.keys(e).sort();let s="";for(const i of t)s+=M(e[i]);return s}};function I(){return m(u.MAKE_SIGN_FAIL,"make sign fail")}class k{constructor(e){Object.defineProperty(this,"api",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"context",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"logger",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),this.api=d.create({baseURL:e.host,headers:{"x-developer":e.developer},withCredentials:!0}),this.context=e.context,this.logger=e.logger}async request(e){try{const{needSign:t=!0,...s}=e;if(s.headers||(s.headers={}),s.headers.platform="web",t&&"POST"===e.method?.toUpperCase()&&s.data){if(null===this.context.loginUser)return this.logger.warn("HttpClient needs make sign but not login"),I();try{const e=await(async(e,t)=>{const s=await M(e);return await L(s,t)})(s.data,this.context.loginUser.secretKey);s.headers.sign=e}catch(e){return this.logger.error("HttpClient make sign error",e),I()}}this.context.loginUser&&(s.headers["X-Sid"]=this.context.loginUser.sessionId);const i=await this.api(s),n=i.data;return n.code===u.SUCCESS?{ok:!0,data:n.data}:(this.logger.info("HttpClient server error",i),{ok:!1,code:n.code,msg:n.msg,msg_i18n:n.msg_i18n})}catch{return{ok:!1,code:u.NETWORK_ERROR,msg:"network error"}}}get(e,t,s){return this.request({url:e,method:"GET",params:t,...s})}post(e,t,s){return this.request({url:e,method:"POST",data:t,...s})}}function U(e){return`${e}`.padStart(2,"0")}class x{constructor(){Object.defineProperty(this,"level",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"logHandler",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),this.level=h.error,this.logHandler=this.createLogHandler()}getPriority(e){switch(e){case h.error:return 3;case h.warning:return 2;case h.info:return 1;default:return 0}}createLogHandler(){return(e,...t)=>{const s=new Date,i=`TypeX >> [${`${s.getFullYear()}-${U(s.getMonth()+1)}-${U(s.getDate())} ${U(s.getHours())}:${U(s.getMinutes())}:${U(s.getSeconds())}.${s.getMilliseconds()}`}]`;switch(e){case h.error:console.error(i,"[ERR]",...t);break;case h.warning:console.warn(i,"[WARN]",...t);break;case h.info:console.info(i,"[INFO]",...t);break;default:console.log(i,...t)}}}log(e,...t){this.getPriority(e)>=this.getPriority(this.level)&&this.logHandler(e,...t)}setLogLevel(e){this.level=e,this.logHandler=this.createLogHandler()}info(...e){this.log(h.info,...e)}warn(...e){this.log(h.warning,...e)}error(...e){this.log(h.error,...e)}}class G{constructor(e){Object.defineProperty(this,"context",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"logger",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"emitter",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"feedCache",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"handleKickoff",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),this.context=e.context,this.logger=e.logger,this.emitter=e.emitter,this.feedCache=e.feedCache,this.handleKickoff=e.onKickoff}emitFeedListUpdated(){this.emitter.emit(p.FEED_LIST_UPDATED,{list:this.feedCache.getAll(),is_sync_completed:this.feedCache.isSyncCompleted()})}processCreateFeed(e){this.feedCache.unshift(e.content),this.emitFeedListUpdated()}processUpdateFeed(e){const t=e.content,s=this.feedCache.getByChat(t.chat_id,t.thread_id);if(null===s)return;const i={...s,...t};this.feedCache.update(i),this.emitFeedListUpdated()}processDeleteFeed(e){this.feedCache.remove(e.content.id)&&this.emitFeedListUpdated()}processAddMessage(t){if(null===this.context.loginUser)return;const s=this.context.loginUser.userId,i=t.content;if(i.hide_ids.includes(s))return;const r=this.feedCache.getByChat(i.chat_id,i.thread_id);if(null!==r){if(i.no_last_msg!==e.yes){let t=!1,o=!1;const a={};if(i.message_kind_id!==n.system&&i.sender_id!==s&&i.no_read!==e.yes){t=!0;const e=new Set(r.unread_message_ids);e.add(i.id),a.unread_message_ids=[...e],a.badge=e.size}if(r.last_message_position<i.position&&(t=!0,o=!0,a.last_message_id=i.id,a.last_message_position=i.position,a.last_message_sender_id=i.sender_id,a.last_message_send_at=i.send_at,a.last_message_kind_id=i.message_kind_id,a.last_message_type_id=i.message_type_id,a.last_message=i.content,a.last_message_operation=i.operation,a.last_message_operation_user_id=i.operation_user_id),t){const e={...r,...a};o?this.feedCache.unshift(e):this.feedCache.update(e),this.emitFeedListUpdated()}}this.emitter.emit(p.MESSAGE_RECEIVED,{feed_id:r.id,message:i})}}processUpdateMessage(e){const t=e.content,s=this.feedCache.getByChat(t.chat_id,t.thread_id);if(null!==s&&null!=t.operation){let e=!1;const i={};if(t.operation===a.recall||t.operation===a.destroy){if(null!=s.unread_message_ids&&s.unread_message_ids.includes(t.id)){e=!0;const n=new Set(s.unread_message_ids);n.delete(t.id),i.unread_message_ids=[...n],i.badge=i.unread_message_ids.length}s.last_message_id===t.id&&(e=!0,i.last_message=t.content??"{}",i.last_message_operation=t.operation,i.last_message_operation_user_id=t.operation_user_id??"0")}else t.operation===a.edit&&s.last_message_id===t.id&&(e=!0,i.last_message_kind_id=t.message_kind_id,i.last_message_type_id=t.message_type_id,i.last_message=t.content,i.last_message_operation=t.operation,i.last_message_operation_user_id=t.operation_user_id);e&&(this.feedCache.update({...s,...i}),this.emitFeedListUpdated()),t.operation===a.recall?this.emitter.emit(p.MESSAGE_RECALLED,{message_ids:[t.id]}):t.operation===a.edit?null!=t.content&&null!=t.edited_at&&null!=t.message_kind_id&&null!=t.message_type_id&&null!=t.operation_user_id&&this.emitter.emit(p.MESSAGE_EDITED,{chat_id:t.chat_id,content:t.content,edited_at:t.edited_at,id:t.id,message_kind_id:t.message_kind_id,message_type_id:t.message_type_id,operation:t.operation,operation_user_id:t.operation_user_id,thread_id:t.thread_id}):t.operation===a.destroy&&this.emitter.emit(p.MESSAGE_DESTROYED,{feed_id:s.id,message_ids:[t.id]})}}processDeleteMessage(e){const t=e.content,s=this.feedCache.getByChat(t.chat_id,t.thread_id);if(null===s)return;let i=!1;const n={};s.last_message_id===t.id&&(i=!0,n.last_message=t.content??"{}",n.last_message_operation=t.operation,n.last_message_operation_user_id=t.operation_user_id??"0"),i&&(this.feedCache.update({...s,...n}),this.emitFeedListUpdated()),this.emitter.emit(p.MESSAGE_DESTROYED,{feed_id:s.id,message_ids:[t.id]})}processOpenClockMessage(e){const t=e.content,s=this.feedCache.getByChat(t.chat_id,t.thread_id);if(null!==s&&Array.isArray(t.msgs_open_clock)){const e=t.msgs_open_clock.map(e=>e.message_id);this.emitter.emit(p.MESSAGE_OPEN_CLOCK,{feed_id:s.id,message_ids:e})}}processPushLiveMessage(e){this.emitter.emit(p.ROOM_MESSAGE_RECEIVED,{room_id:e.content.room_id,content:e.content.message})}processPushSystemNotice(e){this.emitter.emit(p.SYSTEM_NOTICE_RECEIVED,{content:e.content})}processReadMessage(e){if(null===this.context.loginUser)return;const t=this.context.loginUser.userId,s=e.content,i=this.feedCache.getByChat(s.chat_id,s.thread_id);if(null===i)return;let n=!1;const r={};if(s.reader_ids.includes(t)&&s.message_ids.length>0){n=!0;const e=new Set(i.unread_message_ids);s.message_ids.forEach(t=>{e.delete(t)}),r.unread_message_ids=[...e],r.badge=e.size}n&&(this.feedCache.update({...i,...r}),this.emitFeedListUpdated()),this.emitter.emit(p.MESSAGE_RECEIPT_RECEIVED,{feed_id:i.id,message_ids:s.message_ids,reader_user_ids:s.reader_ids})}processKickOutDevice(){this.handleKickoff()}processGroupMember(e){const s=e.content,i=this.feedCache.getByChat(s.chat_id,"0");if(null===i)return;const n=new Set(i.chat_member),r=e.type===t.ADD_GROUP_MEMBER,o=e.type===t.DEL_GROUP_MEMBER;s.chat_member.forEach(e=>{r?n.add(e.chat_id):o&&n.delete(e.chat_id)}),this.feedCache.update({...i,chat_member:[...n]}),this.emitFeedListUpdated()}processUpdateGroup(e){const t=e.content,s=this.feedCache.getByChat(t.chat_id,"0");if(null===s)return;let i=!1;const n={};null!=t.avatar&&(i=!0,n.avatar=t.avatar),null!=t.name&&(i=!0,n.name=t.name),i&&(this.feedCache.update({...s,...n}),this.emitFeedListUpdated())}processUpdateUserData(e){const t=e.content,s=this.feedCache.getByTargetId(t.id);if(s.length>0){const e={};if(null!=t.avatar&&(e.avatar=t.avatar),null!=t.first_name||null!=t.last_name){let s=t.first_name??"";null!=t.last_name&&(s=s.length>0?`${s} ${t.last_name}`:t.last_name),e.name=s}for(const t of s)this.feedCache.update({...t,...e});this.emitFeedListUpdated()}}processUpdateMessageReaction(e){const t=e.content,s=this.feedCache.getByChat(t.chat_id,t.thread_id);null!==s&&this.emitter.emit(p.MESSAGE_REACTION_UPDATED,{feed_id:s.id,message_id:t.message_id,reactions:t.reactions})}process(e){switch(this.logger.info("PushMessageProcessor process",e),e.type){case t.CREATE_FEED:this.processCreateFeed(e);break;case t.UPDATE_FEED:this.processUpdateFeed(e);break;case t.DELETE_FEED:this.processDeleteFeed(e);break;case t.ADD_MESSAGE:this.processAddMessage(e);break;case t.UPDATE_MESSAGE:this.processUpdateMessage(e);break;case t.DELETE_MESSAGE:this.processDeleteMessage(e);break;case t.PUSH_LIVE_MESSAGE:this.processPushLiveMessage(e);break;case t.MSG_OPEN_CLOCK:this.processOpenClockMessage(e);break;case t.PUSH_SYSTEM_NOTICE:this.processPushSystemNotice(e);break;case t.READ_MESSAGE:this.processReadMessage(e);break;case t.KICK_OUT_DEVICE:this.processKickOutDevice();break;case t.ADD_GROUP_MEMBER:case t.DEL_GROUP_MEMBER:this.processGroupMember(e);break;case t.UPDATE_GROUP:this.processUpdateGroup(e);break;case t.UPDATE_USER_DATA:this.processUpdateUserData(e);break;case t.UPDATE_MESSAGE_REACTION:this.processUpdateMessageReaction(e)}}}const N=50;function F(e){return new Promise(t=>{setTimeout(t,e)})}class j{constructor(){Object.defineProperty(this,"obtained",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"abortLockObtain",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),this.obtained=!1,this.abortLockObtain=null}async requestLock(e={}){const{timeoutMs:t=0,retryIntervalMs:s=N}=e,i=Date.now();for(;;){if(await this.requestLockOnce())return!0;if(t<=0)return!1;const e=t-(Date.now()-i);if(e<=0)return!1;await F(Math.min(s,e))}}async requestLockOnce(){if(this.obtained)return!0;if("undefined"==typeof navigator||!navigator.locks)return!1;let e=()=>{};const t=new Promise(t=>{e=t}),s=new Promise(e=>{this.abortLockObtain=e});try{navigator.locks.request("typex-sdk",{ifAvailable:!0},async t=>{t?(this.obtained=!0,e(!0),await s):(this.abortLockObtain=null,e(!1))}).catch(()=>{this.abortLockObtain=null,e(!1)})}catch{this.abortLockObtain=null,e(!1)}return await t}releaseLock(){this.obtained=!1,null!==this.abortLockObtain&&(this.abortLockObtain(),this.abortLockObtain=null)}}class K{static set(e){localStorage.setItem(this.key,JSON.stringify(e))}static get(){try{const e=localStorage.getItem(this.key);if(!e)return null;return JSON.parse(e)}catch{return null}}static clear(){localStorage.removeItem(this.key)}}Object.defineProperty(K,"key",{enumerable:!0,configurable:!0,writable:!0,value:"__typex_sdk_data__"});const q="__typex_sdk_tab_session_message__";function H(){return"undefined"!=typeof crypto&&"randomUUID"in crypto?crypto.randomUUID():`${Date.now()}-${Math.random().toString(36).slice(2)}`}class B{constructor(e){Object.defineProperty(this,"tabId",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"channel",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"closed",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"handledTakeoverIds",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"handledSessionRequestIds",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"pendingSessionRequests",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"onTakeoverRequest",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"getCurrentSession",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"logger",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),this.tabId=H(),this.channel=null,this.closed=!1,this.handledTakeoverIds=new Set,this.handledSessionRequestIds=new Set,this.pendingSessionRequests=new Map,this.onTakeoverRequest=e.onTakeoverRequest,this.getCurrentSession=e.getCurrentSession??null,this.logger=e.logger??null,this.handleBroadcastMessage=this.handleBroadcastMessage.bind(this),this.handleStorageMessage=this.handleStorageMessage.bind(this),"undefined"!=typeof BroadcastChannel&&(this.channel=new BroadcastChannel("typex-sdk-tab-session"),this.channel.onmessage=this.handleBroadcastMessage),"undefined"!=typeof window&&window.addEventListener("storage",this.handleStorageMessage)}requestTakeover(){this.publish({type:"takeover",senderTabId:this.tabId,takeoverId:H(),createdAt:Date.now()})}requestCurrentSession(e=500){if(this.closed)return Promise.resolve(null);const t=H();return new Promise(s=>{const i=setTimeout(()=>{this.pendingSessionRequests.delete(t),s(null)},e);this.pendingSessionRequests.set(t,{resolve:s,timeout:i}),this.publish({type:"session-request",senderTabId:this.tabId,requestId:t,createdAt:Date.now()})})}destroy(){this.closed||(this.closed=!0,this.pendingSessionRequests.forEach(e=>{clearTimeout(e.timeout),e.resolve(null)}),this.pendingSessionRequests.clear(),this.channel&&(this.channel.close(),this.channel=null),"undefined"!=typeof window&&window.removeEventListener("storage",this.handleStorageMessage))}publish(e){if(!this.closed&&(this.channel&&this.channel.postMessage(e),"session-response"!==e.type&&"undefined"!=typeof localStorage))try{localStorage.setItem(q,JSON.stringify({...e,storageNonce:H()}))}catch(e){this.logger?.warn("TabSessionCoordinator storage publish failed",e)}}handleBroadcastMessage(e){this.handleMessage(e.data)}handleStorageMessage(e){if(e.key===q&&e.newValue)try{this.handleMessage(JSON.parse(e.newValue))}catch(e){this.logger?.warn("TabSessionCoordinator storage parse failed",e)}}handleMessage(e){if(!this.closed&&function(e){if(!e||"object"!=typeof e)return!1;const t=e;return"string"==typeof t.senderTabId&&("takeover"===t.type?"string"==typeof t.takeoverId&&"number"==typeof t.createdAt:"session-request"===t.type?"string"==typeof t.requestId&&"number"==typeof t.createdAt:"session-response"===t.type&&"string"==typeof t.requesterTabId&&"string"==typeof t.requestId&&"number"==typeof t.createdAt&&function(e){if(!e||"object"!=typeof e)return!1;const t=e,s=t.loginUser;return(null===t.deviceId||"string"==typeof t.deviceId)&&!!s&&"string"==typeof s.userId&&"string"==typeof s.secretKey&&"string"==typeof s.sessionId}(t.session))}(e)&&e.senderTabId!==this.tabId){if("takeover"===e.type){if(this.handledTakeoverIds.has(e.takeoverId))return;return this.handledTakeoverIds.add(e.takeoverId),void this.onTakeoverRequest()}if("session-request"===e.type){const t=`${e.senderTabId}:${e.requestId}`;if(this.handledSessionRequestIds.has(t))return;this.handledSessionRequestIds.add(t);const s=this.getCurrentSession?.();if(!s)return;return void this.publish({type:"session-response",senderTabId:this.tabId,requesterTabId:e.senderTabId,requestId:e.requestId,createdAt:Date.now(),session:s})}if("session-response"===e.type){if(e.requesterTabId!==this.tabId)return;const t=this.pendingSessionRequests.get(e.requestId);if(!t)return;clearTimeout(t.timeout),this.pendingSessionRequests.delete(e.requestId),t.resolve(e.session)}}}}class ${constructor(){Object.defineProperty(this,"version",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),this.version=0}increment(){this.version++}get(){return this.version}check(e){return e===this.version}}class V extends w{constructor(e){super(),Object.defineProperty(this,"context",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"version",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"singletonLock",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"tabSessionCoordinator",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"restoreLoginPromise",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"logger",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"httpClient",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"feedCache",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"ws",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"pushMessageProcessor",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),this.context={isLogin:!1,loginUser:null,isReady:!1,deviceId:null},this.version=new $,this.singletonLock=new j,this.logger=new x,this.restoreLoginPromise=null,this.tabSessionCoordinator=new B({logger:this.logger,getCurrentSession:()=>this.getTransferableLoginSession(),onTakeoverRequest:()=>{this.deactivateByTakeover()}}),this.httpClient=new k({host:e.httpHost,context:this.context,logger:this.logger,developer:e.developer}),this.feedCache=new D,this.ws=new O({host:e.websocketHost,context:this.context,logger:this.logger}),this.pushMessageProcessor=new G({context:this.context,logger:this.logger,emitter:this,feedCache:this.feedCache,onKickoff:()=>{this.afterLogout()}}),this.init()}init(){this.loadContext(),this.ws.on("message",e=>{this.pushMessageProcessor.process(e)}),this.ws.on("kickoff",()=>{this.afterLogout()}),setTimeout(()=>{this.restoreLoginFromActiveTab()},0)}getTransferableLoginSession(){return this.context.isLogin&&null!==this.context.loginUser?{deviceId:this.context.deviceId,loginUser:{...this.context.loginUser}}:null}async restoreLoginFromActiveTab(){if(this.restoreLoginPromise)return this.restoreLoginPromise;this.restoreLoginPromise=this.doRestoreLoginFromActiveTab();try{return await this.restoreLoginPromise}finally{this.restoreLoginPromise=null}}async doRestoreLoginFromActiveTab(){if(this.context.isLogin)return!0;const e=await this.tabSessionCoordinator.requestCurrentSession(500);if(!e||this.context.isLogin)return this.context.isLogin;this.tabSessionCoordinator.requestTakeover();return!await this.singletonLock.requestLock({timeoutMs:3e3,retryIntervalMs:50})||this.context.isLogin?this.context.isLogin:(this.context.isLogin=!0,this.context.loginUser=e.loginUser,e.deviceId&&(this.context.deviceId=e.deviceId),this.applyLoginStatus(),!0)}async requestDeviceId(){if(this.context.deviceId)return!0;const e=await this.httpClient.post("/device_api/device_id",{platform:"web",hash_str:""},{needSign:!1});return!!e.ok&&(this.context.deviceId=e.data,this.saveContext(),!0)}saveContext(){const{context:e}=this;K.set({deviceId:e.deviceId})}loadContext(){const e=K.get();e&&e.deviceId&&(this.context.deviceId=e.deviceId)}applyLoginStatus(){this.version.increment(),this.saveContext(),this.context.isLogin?(this.ws.connect(),this.loadFeedList(),this.context.isReady=!0,this.emit(p.SDK_READY)):(this.ws.disconnect(),this.feedCache.reset(),this.singletonLock.releaseLock(),this.context.isReady=!1,this.emit(p.SDK_NOT_READY))}async loadFeedList(){const e=this.version.get(),t={refresh_at:null,feed_id:null};for(;;){const s=await this.httpClient.get("/feed",{limit:500,last_refresh_at:t.refresh_at??void 0,last_feed_id:t.feed_id??void 0});if(!this.version.check(e))break;if(!s.ok||null===s.data)break;if(t.refresh_at=s.data.refresh_at,t.feed_id=s.data.last_feed_id,(s.data.feed_list??[]).forEach(e=>{this.feedCache.push(e)}),!s.data.has_more)break}this.version.check(e)&&(this.feedCache.markSyncComplete(),this.emit(p.FEED_LIST_UPDATED,{list:this.feedCache.getAll(),is_sync_completed:!0}))}isReady(){return this.context.isReady}setLogLevel(e){this.logger.setLogLevel(e)}async login(e){if(this.context.isLogin)return b(null);if(await this.restoreLoginFromActiveTab()||this.context.isLogin)return b(null);if(await this.requestDeviceId(),!this.context.deviceId)return this.logger.error("Get deviceId failed"),m(u.SDK_ERROR,"Get deviceId failed");const t=await this.httpClient.post("/user/session/login",{userCode:e.user_code,device_id:this.context.deviceId},{needSign:!1});if(!t.ok)return t;this.tabSessionCoordinator.requestTakeover();return await this.singletonLock.requestLock({timeoutMs:3e3,retryIntervalMs:50})?(this.context.isLogin=!0,this.context.loginUser={userId:t.data.id,secretKey:t.data.key,sessionId:e.user_code},this.applyLoginStatus(),b(null)):(this.logger.error("Another active TypeX SDK instance detected"),m(u.REQUEST_SINGLETON_LOCK_FAIL,"Another active TypeX SDK instance detected"))}async logout(){if(!this.context.isLogin)return b(null);const e=await this.httpClient.get("/user/logout");return e.ok?(this.afterLogout(),b(null)):e}async afterLogout(){this.context.isLogin=!1,this.context.loginUser=null,this.applyLoginStatus()}deactivateByTakeover(){this.context.isLogin||this.context.isReady?(this.logger.info("Current TypeX SDK instance deactivated by another tab"),this.afterLogout()):this.singletonLock.releaseLock()}getLoginUser(){return null===this.context.loginUser?null:this.context.loginUser.userId}async createSingleChatFeed(e){return await this.httpClient.post("/chat/single",{receiver_id:e})}async deleteFeed(e){return await this.httpClient.post("/feed/delete",{feed_id_list:[e],delete_peer:!0})}async getFeedList(){return b({list:this.feedCache.getAll(),is_sync_completed:this.feedCache.isSyncCompleted()})}async getFeedDetail(e){return b(await this.feedCache.waitFor(e))}async getFeedMemberList(e){const t=await this.feedCache.get(e);return null!==t&&t.chat_member.length>0?await this.httpClient.post("/chat/chatter_info",{chatters:{[t.chat_id]:t.chat_member}}):b([])}async getUserByUids(e){const t=await this.httpClient.post("/user/users_info",e);return t.ok?b(t.data.map(e=>({id:e.id}))):t}getDomain(e){const[t,s]=l,i=T(t),n=T(s);for(const r of e){if(i.test(r.content))return t;if(n.test(r.content))return s}}appendXsid(e){if(!this.context.loginUser?.sessionId)return e;const t=this.context.loginUser.sessionId,s=this.getDomain(e);return s?e.map(e=>{const i=v(e.content,s,e=>((e,t,s)=>{const i=encodeURIComponent(t),n=encodeURIComponent(s),r=e.indexOf("#"),o=r>=0?e.slice(0,r):e,a=r>=0?e.slice(r):"",d=new RegExp(`([?&])${C(i)}=[^&#]*`);if(d.test(o))return o.replace(d,`$1${i}=${n}`)+a;const c=o.includes("?")?"&":"?";return`${o}${c}${i}=${n}${a}`})(e,"xsid",t));return{...e,content:i}}):e}async markFeedMessageAsRead(t){const s=this.feedCache.get(t);if(!s)return b(!1);if(!(await this.httpClient.post("/feed/update",{id:s.id,mark_unread:e.yes})).ok)return b(!1);return(await this.httpClient.post("/message/read",{chat_id:s.chat_id,thread_id:s.thread_id})).ok?b(!0):b(!1)}async getMessagesByIds(e,t){const s=this.feedCache.get(e);if(!s||!Array.isArray(t)||0===t.length)return b([]);const i=await this.httpClient.post("/message/get_by_msgid",{chat_msg_id_map:{[s.chat_id]:t}});if(i.ok){return b(this.appendXsid(i.data[s.chat_id]))}return b([])}async getFeedMessageList(e){const t=await this.getFeedDetail(e.feed_id);if(t.ok&&t.data){const s=t.data,{chat_id:i,first_position:n,last_message_position:r}=s,{positions:o,nextPosition:a,hasMore:d}=(e=>{const t=[];if(e.direction===g.up){let s=e.startPosition??e.maxPosition;for(;t.length<e.limit&&s>=e.minPosition;)t.push(s),s--;const i=s>=e.minPosition;let n;return i&&(n=s),{positions:t,nextPosition:n,hasMore:i}}{let s=e.startPosition??e.minPosition;for(;t.length<e.limit&&s<=e.maxPosition;)t.push(s),s++;const i=s<=e.maxPosition;let n;return i&&(n=s),{positions:t,nextPosition:n,hasMore:i}}})({maxPosition:r,minPosition:n,startPosition:e.message_position,limit:e.limit,direction:e.direction??g.up});if(o.length>0){const e=await this.httpClient.post("/message/get_by_position",{chat_position:{[i]:o}},{needSign:!1});if(e.ok&&e.data[i]){return b({has_more:d,list:this.appendXsid(e.data[i].reverse()),next_message_position:a})}}}return b({has_more:!1,list:[]})}createCustomMessage(e){if(null===this.context.loginUser)return m(u.SDK_ERROR,"not login");const t=this.feedCache.get(e.feed_id);if(null===t)return m(u.SDK_ERROR,"not found feed");const s=(new Date).toISOString();var i;return b({id:"",chat_id:t.chat_id,thread_id:t.thread_id,position:t.last_message_position,sender_id:this.context.loginUser.userId,message_kind_id:n.text,message_type_id:r.custom,send_at:s,edited_at:s,reader_ids:[],unreader_ids:[],hide_ids:[],operation:a.normal,operation_user_id:"0",content:(i={client_msg_id:e.client_msg_id,content:e.content},JSON.stringify({client_msg_id:i.client_msg_id,content:JSON.stringify(i.content)})),reactions:[]})}async sendMessageToFeed(e){if(e.message_type_id===r.custom){const t=y(e.content);return this.httpClient.post("/message/send_custom",{chat_id:e.chat_id,thread_id:e.thread_id,client_id:t.client_msg_id,content:null==t.content?void 0:JSON.stringify(t.content)})}return m(u.SDK_ERROR,"not support")}async sendMessageReadReceipt(e){const t=this.feedCache.get(e.feed_id);return null===t?m(u.SDK_ERROR,"not found feed"):await this.httpClient.post("/message/read",{chat_id:t.chat_id,message_ids:e.message_ids})}async joinRoom(e){return await this.httpClient.post("/liveshow/join",{room_id:e})}async setMute(t){const s=await this.httpClient.post("/feed/update",{id:t.feedId,is_mute:t.isMute?e.yes:e.no});return s.ok?s.data:null}async leaveRoom(e){return await this.httpClient.post("/liveshow/leave",{room_id:e})}async getJoinedRooms(){return await this.httpClient.get("/liveshow/joined_rooms")}async getRoomRecentMessageList(e){const t=await this.httpClient.get("/liveshow/get_recent_message",{room_id:e});return t.ok?b(t.data):t}async sendMessageToRoom(e){return await this.httpClient.post("/liveshow/send_message",{room_id:e.room_id,content:e.content})}}const W=new Map;const Y={parseSystemMessageContent:e=>{const t=S(e);return null!==t?{text:t.text,text_i18n:t.text_i18n}:{}},parseTextMessageContent:e=>{const t=S(e);return null!==t?{text:t.text,client_msg_id:t.client_msg_id}:{}},parseCustomMessageContent:y};exports.ChatSDK=V,exports.create=function(e,t){let s=W.get(e);return void 0===s&&(s=new V(t),W.set(e,s)),s},exports.enums=_,exports.events=E,exports.interfaces=f,exports.utils=Y;
package/package.json CHANGED
@@ -1,8 +1,11 @@
1
1
  {
2
2
  "name": "@typexim/web-sdk",
3
- "version": "0.0.5-alpha.9",
3
+ "version": "0.0.7",
4
4
  "private": false,
5
- "repository": "git@github.com:secure-typex/typex-web-sdk.git",
5
+ "repository": {
6
+ "type": "git",
7
+ "url": "git+ssh://git@github.com/secure-typex/typex-web-sdk.git"
8
+ },
6
9
  "license": "MIT",
7
10
  "type": "module",
8
11
  "exports": {
@@ -22,10 +25,12 @@
22
25
  "types": "./dist/types/index.d.ts",
23
26
  "scripts": {
24
27
  "build": "cross-env MODE=prod rollup -c",
25
- "dev": "cross-env MODE=dev rollup -c -w"
28
+ "dev": "cross-env MODE=dev rollup -c -w",
29
+ "publish:alpha": "npm publish --tag alpha",
30
+ "publish:latest": "npm publish --tag latest"
26
31
  },
27
32
  "dependencies": {
28
- "axios": "1.11.0",
33
+ "axios": "1.18.1",
29
34
  "crypto-js": "4.2.0"
30
35
  },
31
36
  "devDependencies": {
@@ -38,5 +43,8 @@
38
43
  },
39
44
  "engines": {
40
45
  "node": ">=20.0.0"
46
+ },
47
+ "publishConfig": {
48
+ "access": "public"
41
49
  }
42
50
  }
@@ -0,0 +1,232 @@
1
+ import assert from 'node:assert/strict';
2
+ import { access, readdir, readFile, writeFile } from 'node:fs/promises';
3
+ import { dirname, resolve } from 'node:path';
4
+ import { test } from 'node:test';
5
+ import { fileURLToPath } from 'node:url';
6
+
7
+ const channels = new Set();
8
+ const storageListeners = new Set();
9
+ const storageData = new Map();
10
+
11
+ class MockBroadcastChannel {
12
+ constructor(name) {
13
+ this.name = name;
14
+ this.onmessage = null;
15
+ channels.add(this);
16
+ }
17
+
18
+ postMessage(message) {
19
+ for (const channel of channels) {
20
+ if (channel !== this && channel.name === this.name && channel.onmessage) {
21
+ channel.onmessage({ data: message });
22
+ }
23
+ }
24
+ }
25
+
26
+ close() {
27
+ channels.delete(this);
28
+ }
29
+ }
30
+
31
+ class MockWebSocket {
32
+ static OPEN = 1;
33
+
34
+ constructor() {
35
+ this.OPEN = 1;
36
+ this.readyState = 1;
37
+ setTimeout(() => this.onopen?.(), 0);
38
+ }
39
+
40
+ send() {}
41
+
42
+ close() {}
43
+ }
44
+
45
+ function installBrowserMocks() {
46
+ channels.clear();
47
+ storageListeners.clear();
48
+ storageData.clear();
49
+
50
+ let lockHeld = false;
51
+ Object.defineProperty(globalThis, 'navigator', {
52
+ configurable: true,
53
+ value: {
54
+ locks: {
55
+ request: async (_name, options, callback) => {
56
+ if (lockHeld && options?.ifAvailable) {
57
+ return callback(null);
58
+ }
59
+
60
+ lockHeld = true;
61
+ try {
62
+ return await callback({});
63
+ } finally {
64
+ lockHeld = false;
65
+ }
66
+ },
67
+ },
68
+ },
69
+ });
70
+ globalThis.BroadcastChannel = MockBroadcastChannel;
71
+ globalThis.WebSocket = MockWebSocket;
72
+ globalThis.window = {
73
+ addEventListener: (type, listener) => {
74
+ if (type === 'storage') storageListeners.add(listener);
75
+ },
76
+ removeEventListener: (type, listener) => {
77
+ if (type === 'storage') storageListeners.delete(listener);
78
+ },
79
+ };
80
+ globalThis.localStorage = {
81
+ getItem: (key) => storageData.get(key) ?? null,
82
+ setItem: (key, value) => {
83
+ const oldValue = storageData.get(key) ?? null;
84
+ storageData.set(key, value);
85
+ for (const listener of storageListeners) {
86
+ listener({ key, oldValue, newValue: value });
87
+ }
88
+ },
89
+ removeItem: (key) => storageData.delete(key),
90
+ };
91
+ }
92
+
93
+ function createSdk(ChatSDK) {
94
+ const sdk = new ChatSDK({
95
+ httpHost: 'https://example.test',
96
+ websocketHost: 'wss://example.test',
97
+ });
98
+
99
+ sdk.httpClient.get = async () => ({
100
+ ok: true,
101
+ data: null,
102
+ });
103
+
104
+ return sdk;
105
+ }
106
+
107
+ async function patchDistTestImports(dirUrl) {
108
+ const entries = await readdir(dirUrl, { withFileTypes: true });
109
+
110
+ await Promise.all(
111
+ entries.map(async (entry) => {
112
+ const entryUrl = new URL(
113
+ `${entry.name}${entry.isDirectory() ? '/' : ''}`,
114
+ dirUrl,
115
+ );
116
+
117
+ if (entry.isDirectory()) {
118
+ await patchDistTestImports(entryUrl);
119
+ return;
120
+ }
121
+
122
+ if (!entry.name.endsWith('.js')) {
123
+ return;
124
+ }
125
+
126
+ const source = await readFile(entryUrl, 'utf8');
127
+ const patched = await patchRelativeImports(source, entryUrl);
128
+
129
+ if (patched !== source) {
130
+ await writeFile(entryUrl, patched);
131
+ }
132
+ }),
133
+ );
134
+ }
135
+
136
+ async function pathExists(path) {
137
+ try {
138
+ await access(path);
139
+ return true;
140
+ } catch {
141
+ return false;
142
+ }
143
+ }
144
+
145
+ async function patchRelativeImports(source, sourceUrl) {
146
+ const sourcePath = fileURLToPath(sourceUrl);
147
+ const sourceDir = dirname(sourcePath);
148
+ const importRegex =
149
+ /(?<prefix>from\s+['"])(?<specifier>\.\.?\/[^'"]+)(?<suffix>['"])/g;
150
+ const matches = [...source.matchAll(importRegex)];
151
+ let patched = source;
152
+
153
+ for (const match of matches) {
154
+ const { prefix, specifier, suffix } = match.groups;
155
+
156
+ if (specifier.endsWith('.js')) {
157
+ continue;
158
+ }
159
+
160
+ const targetPath = resolve(sourceDir, specifier);
161
+ let nextSpecifier = specifier;
162
+
163
+ if (await pathExists(`${targetPath}.js`)) {
164
+ nextSpecifier = `${specifier}.js`;
165
+ } else if (await pathExists(resolve(targetPath, 'index.js'))) {
166
+ nextSpecifier = `${specifier}/index.js`;
167
+ }
168
+
169
+ if (nextSpecifier !== specifier) {
170
+ patched = patched.replaceAll(
171
+ `${prefix}${specifier}${suffix}`,
172
+ `${prefix}${nextSpecifier}${suffix}`,
173
+ );
174
+ }
175
+ }
176
+
177
+ return patched;
178
+ }
179
+
180
+ test('login restores an active tab session before calling session login API', async () => {
181
+ installBrowserMocks();
182
+
183
+ await patchDistTestImports(new URL('../dist-test/', import.meta.url));
184
+ const { default: ChatSDK } = await import('../dist-test/modules/ChatSDK.js');
185
+
186
+ const oldSdk = createSdk(ChatSDK);
187
+ oldSdk.context.deviceId = 'device-1';
188
+ oldSdk.context.isLogin = true;
189
+ oldSdk.context.isReady = true;
190
+ oldSdk.context.loginUser = {
191
+ userId: 'user-1',
192
+ secretKey: 'secret-1',
193
+ sessionId: 'session-1',
194
+ };
195
+ await oldSdk.singletonLock.requestLock();
196
+
197
+ const newSdk = createSdk(ChatSDK);
198
+ let sessionLoginApiCalled = false;
199
+ newSdk.httpClient.post = async (url) => {
200
+ if (url === '/user/session/login') {
201
+ sessionLoginApiCalled = true;
202
+ }
203
+ return {
204
+ ok: false,
205
+ code: -1,
206
+ msg: 'unexpected post',
207
+ };
208
+ };
209
+
210
+ try {
211
+ const res = await newSdk.login({
212
+ user_code: 'session-1',
213
+ });
214
+
215
+ assert.equal(res.ok, true);
216
+ assert.equal(sessionLoginApiCalled, false);
217
+ assert.equal(newSdk.context.isLogin, true);
218
+ assert.equal(newSdk.context.isReady, true);
219
+ assert.deepEqual(newSdk.context.loginUser, {
220
+ userId: 'user-1',
221
+ secretKey: 'secret-1',
222
+ sessionId: 'session-1',
223
+ });
224
+ assert.equal(oldSdk.context.isLogin, false);
225
+ assert.equal(oldSdk.context.isReady, false);
226
+ } finally {
227
+ await oldSdk.afterLogout();
228
+ await newSdk.afterLogout();
229
+ oldSdk.tabSessionCoordinator.destroy();
230
+ newSdk.tabSessionCoordinator.destroy();
231
+ }
232
+ });
@@ -0,0 +1,75 @@
1
+ import assert from 'node:assert/strict';
2
+ import { test } from 'node:test';
3
+
4
+ import SingletonLock from '../dist-test/modules/SingletonLock.js';
5
+
6
+ function installMockLocks(sequence) {
7
+ let callIndex = 0;
8
+ Object.defineProperty(globalThis, 'navigator', {
9
+ configurable: true,
10
+ value: {
11
+ locks: {
12
+ request: (_name, _options, callback) => {
13
+ const available = sequence[Math.min(callIndex, sequence.length - 1)];
14
+ callIndex += 1;
15
+ Promise.resolve().then(() => callback(available ? {} : null));
16
+ },
17
+ },
18
+ },
19
+ });
20
+ }
21
+
22
+ function installNavigator(value) {
23
+ Object.defineProperty(globalThis, 'navigator', {
24
+ configurable: true,
25
+ value,
26
+ });
27
+ }
28
+
29
+ test('requestLock retries until an old tab releases the singleton lock', async () => {
30
+ installMockLocks([false, false, true]);
31
+
32
+ const lock = new SingletonLock();
33
+ const obtained = await lock.requestLock({
34
+ retryIntervalMs: 1,
35
+ timeoutMs: 50,
36
+ });
37
+
38
+ assert.equal(obtained, true);
39
+ });
40
+
41
+ test('requestLock gives up when the old tab does not release in time', async () => {
42
+ installMockLocks([false]);
43
+
44
+ const lock = new SingletonLock();
45
+ const obtained = await lock.requestLock({
46
+ retryIntervalMs: 1,
47
+ timeoutMs: 5,
48
+ });
49
+
50
+ assert.equal(obtained, false);
51
+ });
52
+
53
+ test('requestLock fails closed when Web Locks is unavailable', async () => {
54
+ installNavigator({});
55
+
56
+ const lock = new SingletonLock();
57
+ const obtained = await lock.requestLock();
58
+
59
+ assert.equal(obtained, false);
60
+ });
61
+
62
+ test('requestLock fails closed when Web Locks throws', async () => {
63
+ installNavigator({
64
+ locks: {
65
+ request: () => {
66
+ throw new Error('locks unavailable');
67
+ },
68
+ },
69
+ });
70
+
71
+ const lock = new SingletonLock();
72
+ const obtained = await lock.requestLock();
73
+
74
+ assert.equal(obtained, false);
75
+ });
@@ -0,0 +1,219 @@
1
+ import assert from 'node:assert/strict';
2
+ import { test } from 'node:test';
3
+
4
+ import TabSessionCoordinator from '../dist-test/modules/TabSessionCoordinator.js';
5
+
6
+ const channels = new Set();
7
+ const storageListeners = new Set();
8
+ const storageData = new Map();
9
+
10
+ class MockBroadcastChannel {
11
+ constructor(name) {
12
+ this.name = name;
13
+ this.onmessage = null;
14
+ channels.add(this);
15
+ }
16
+
17
+ postMessage(message) {
18
+ for (const channel of channels) {
19
+ if (channel !== this && channel.name === this.name && channel.onmessage) {
20
+ channel.onmessage({ data: message });
21
+ }
22
+ }
23
+ }
24
+
25
+ close() {
26
+ channels.delete(this);
27
+ }
28
+ }
29
+
30
+ function installBrowserMocks() {
31
+ channels.clear();
32
+ storageListeners.clear();
33
+ storageData.clear();
34
+ globalThis.BroadcastChannel = MockBroadcastChannel;
35
+ globalThis.window = {
36
+ addEventListener: (type, listener) => {
37
+ if (type === 'storage') storageListeners.add(listener);
38
+ },
39
+ removeEventListener: (type, listener) => {
40
+ if (type === 'storage') storageListeners.delete(listener);
41
+ },
42
+ };
43
+ globalThis.localStorage = {
44
+ getItem: (key) => storageData.get(key) ?? null,
45
+ setItem: (key, value) => {
46
+ const oldValue = storageData.get(key) ?? null;
47
+ storageData.set(key, value);
48
+ for (const listener of storageListeners) {
49
+ listener({ key, oldValue, newValue: value });
50
+ }
51
+ },
52
+ removeItem: (key) => storageData.delete(key),
53
+ };
54
+ }
55
+
56
+ test('a new tab takeover request only notifies the old tab', async () => {
57
+ installBrowserMocks();
58
+
59
+ let oldTabKicked = 0;
60
+ let newTabKicked = 0;
61
+ const oldTab = new TabSessionCoordinator({
62
+ onTakeoverRequest: () => {
63
+ oldTabKicked += 1;
64
+ },
65
+ });
66
+ const newTab = new TabSessionCoordinator({
67
+ onTakeoverRequest: () => {
68
+ newTabKicked += 1;
69
+ },
70
+ });
71
+
72
+ newTab.requestTakeover();
73
+ await new Promise((resolve) => setTimeout(resolve, 0));
74
+
75
+ assert.equal(oldTabKicked, 1);
76
+ assert.equal(newTabKicked, 0);
77
+
78
+ oldTab.destroy();
79
+ newTab.destroy();
80
+ });
81
+
82
+ test('destroyed coordinators ignore later takeover requests', async () => {
83
+ installBrowserMocks();
84
+
85
+ let oldTabKicked = 0;
86
+ const oldTab = new TabSessionCoordinator({
87
+ onTakeoverRequest: () => {
88
+ oldTabKicked += 1;
89
+ },
90
+ });
91
+ const newTab = new TabSessionCoordinator({
92
+ onTakeoverRequest: () => {},
93
+ });
94
+
95
+ oldTab.destroy();
96
+ newTab.requestTakeover();
97
+ await new Promise((resolve) => setTimeout(resolve, 0));
98
+
99
+ assert.equal(oldTabKicked, 0);
100
+
101
+ newTab.destroy();
102
+ });
103
+
104
+ test('a new tab can request the current login session from an old tab', async () => {
105
+ installBrowserMocks();
106
+
107
+ const session = {
108
+ deviceId: 'device-1',
109
+ loginUser: {
110
+ userId: 'user-1',
111
+ secretKey: 'secret-1',
112
+ sessionId: 'session-1',
113
+ },
114
+ };
115
+ const oldTab = new TabSessionCoordinator({
116
+ getCurrentSession: () => session,
117
+ onTakeoverRequest: () => {},
118
+ });
119
+ const newTab = new TabSessionCoordinator({
120
+ onTakeoverRequest: () => {},
121
+ });
122
+
123
+ const restoredSession = await newTab.requestCurrentSession(50);
124
+
125
+ assert.deepEqual(restoredSession, session);
126
+
127
+ oldTab.destroy();
128
+ newTab.destroy();
129
+ });
130
+
131
+ test('login session responses are not persisted through localStorage', async () => {
132
+ installBrowserMocks();
133
+
134
+ const session = {
135
+ deviceId: 'device-1',
136
+ loginUser: {
137
+ userId: 'user-1',
138
+ secretKey: 'secret-1',
139
+ sessionId: 'session-1',
140
+ },
141
+ };
142
+ const oldTab = new TabSessionCoordinator({
143
+ getCurrentSession: () => session,
144
+ onTakeoverRequest: () => {},
145
+ });
146
+ const newTab = new TabSessionCoordinator({
147
+ onTakeoverRequest: () => {},
148
+ });
149
+
150
+ const restoredSession = await newTab.requestCurrentSession(50);
151
+ const storedMessages = [...storageData.values()].map((value) =>
152
+ JSON.parse(value),
153
+ );
154
+
155
+ assert.deepEqual(restoredSession, session);
156
+ assert.equal(
157
+ storedMessages.some((message) => message.type === 'session-response'),
158
+ false,
159
+ );
160
+ assert.equal(
161
+ storedMessages.some((message) =>
162
+ JSON.stringify(message).includes('secret-1'),
163
+ ),
164
+ false,
165
+ );
166
+
167
+ oldTab.destroy();
168
+ newTab.destroy();
169
+ });
170
+
171
+ test('duplicate session requests from fallback channels are answered once', async () => {
172
+ installBrowserMocks();
173
+
174
+ let sessionRequestCount = 0;
175
+ const session = {
176
+ deviceId: 'device-1',
177
+ loginUser: {
178
+ userId: 'user-1',
179
+ secretKey: 'secret-1',
180
+ sessionId: 'session-1',
181
+ },
182
+ };
183
+ const oldTab = new TabSessionCoordinator({
184
+ getCurrentSession: () => {
185
+ sessionRequestCount += 1;
186
+ return session;
187
+ },
188
+ onTakeoverRequest: () => {},
189
+ });
190
+ const newTab = new TabSessionCoordinator({
191
+ onTakeoverRequest: () => {},
192
+ });
193
+
194
+ await newTab.requestCurrentSession(50);
195
+
196
+ assert.equal(sessionRequestCount, 1);
197
+
198
+ oldTab.destroy();
199
+ newTab.destroy();
200
+ });
201
+
202
+ test('requesting a login session returns null when no tab is logged in', async () => {
203
+ installBrowserMocks();
204
+
205
+ const oldTab = new TabSessionCoordinator({
206
+ getCurrentSession: () => null,
207
+ onTakeoverRequest: () => {},
208
+ });
209
+ const newTab = new TabSessionCoordinator({
210
+ onTakeoverRequest: () => {},
211
+ });
212
+
213
+ const restoredSession = await newTab.requestCurrentSession(1);
214
+
215
+ assert.equal(restoredSession, null);
216
+
217
+ oldTab.destroy();
218
+ newTab.destroy();
219
+ });
@@ -0,0 +1,9 @@
1
+ {
2
+ "extends": "./tsconfig.json",
3
+ "compilerOptions": {
4
+ "declaration": false,
5
+ "declarationMap": false,
6
+ "outDir": "dist-test"
7
+ },
8
+ "include": ["src"]
9
+ }