@typexim/agent-js-sdk 1.0.2 → 1.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.es.js +1 -1
- package/dist/index.js +1 -1
- package/package.json +1 -1
package/dist/index.es.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import e from"crypto-js";import t from"axios";import s from"@fingerprintjs/fingerprintjs";import r from"js-cookie";var i,n,o,a,h,c,d,g,E,l;function u(e,t,s){return{ok:!1,code:e||g.SDK_ERROR,msg:t||"sdk error",msg_i18n:s}}function _(e){return{ok:!0,data:e}}!function(e){e[e.KICK_OFF=4001]="KICK_OFF"}(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.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"}(n||(n={})),function(e){e[e.KICK_OUT=0]="KICK_OUT"}(o||(o={})),function(e){e[e.singleChat=1]="singleChat",e[e.groupChat=2]="groupChat"}(a||(a={})),function(e){e[e.normal=0]="normal",e[e.system=1]="system"}(h||(h={})),function(e){e[e.text=0]="text",e[e.image=1]="image",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.contact=9]="contact",e[e.communication=10]="communication",e[e.mixedImageText=11]="mixedImageText",e[e.luckyGift=14]="luckyGift",e[e.fileGroup=15]="fileGroup",e[e.cardMsg=16]="cardMsg"}(c||(c={})),function(e){e[e.normal=0]="normal",e[e.recall=1]="recall"}(d||(d={})),function(e){e[e.NETWORK_ERROR=-1e4]="NETWORK_ERROR",e[e.SDK_ERROR=-10001]="SDK_ERROR"}(g||(g={})),function(e){e.SDK_READY="SDK_READY",e.SDK_NOT_READY="SDK_NOT_READY",e.SDK_KICKOUT="SDK_KICKOUT",e.FEED_UPDATED="FEED_UPDATED",e.MESSAGE_RECEIVED="MESSAGE_RECEIVED",e.MESSAGE_UPDATED="MESSAGE_UPDATED",e.MESSAGE_RECEIPT_RECEIVED="MESSAGE_RECEIPT_RECEIVED"}(E||(E={})),function(e){e[e.up=0]="up",e[e.down=1]="down"}(l||(l={}));const S="[TYPEX_AGENT_JS_SDK]";class p{level=0;setLogLevel(e){this.level=e}getLogLevel(){return this.level}shouldPrint(e){return e>=this.level}debug(...e){this.shouldPrint(0)&&console.debug(`${S}[DEBUG]`,...e)}info(...e){this.shouldPrint(0)&&console.info(`${S}[INFO]`,...e)}warn(...e){this.shouldPrint(1)&&console.warn(`${S}[WARN]`,...e)}error(...e){this.shouldPrint(2)&&console.error(`${S}[ERROR]`,...e)}}function m(e){return(new TextEncoder).encode(e).buffer}async function R(t,s){return window.crypto&&window.crypto.subtle?await async function(e,t){const s=m(t),r=m(e),i=await crypto.subtle.importKey("raw",s,{name:"HMAC",hash:{name:"SHA-256"}},!1,["sign"]),n=await crypto.subtle.sign("HMAC",i,r);return Array.from(new Uint8Array(n)).map(e=>e.toString(16).padStart(2,"0")).join("")}(t,s):function(t,s){const r=e.HmacSHA256(t,s);return e.enc.Hex.stringify(r)}(t,s)}const T=e=>{if(null==e)return"";if("object"!=typeof e||Array.isArray(e)){if(Array.isArray(e)){let t="";for(const s of e)t+=T(s);return t}return"string"==typeof e?e:String(e)}{const t=Object.keys(e).sort();let s="";for(const r of t)s+=T(e[r]);return s}};class C{instance;developer;logger;store;constructor(e,s){this.logger=s.logger,this.store=s.store,this.developer=e.developer;const r=e.baseURL.replace(/\/$/,"");this.instance=t.create({baseURL:r,headers:{...e.defaultHeaders??{}},timeout:e.timeout??3e4}),this.setupInterceptors()}setupInterceptors(){this.instance.interceptors.request.use(e=>(e.headers=e.headers||{},e.headers["Content-Type"]||(e.headers["Content-Type"]="application/json"),e.headers.Platform="web",e.headers.AppID=this.store.appId,e.url?.startsWith("/open")&&(e.headers.Authorization=`Bearer ${this.store.token}`),this.developer&&!e.ignoreDeveloper&&(e.headers["x-developer"]=this.developer),e))}async get(e,t={},s={}){return this.request({url:e,method:"GET",params:t,...s})}async post(e,t,s={}){return this.request({url:e,method:"POST",data:t,...s})}async request(e){try{const{needSign:t,...s}=e;if(t&&"POST"===s.method?.toUpperCase()&&s.data){const t=this.store.currentUser;if(!t){const e="[HttpClient] HttpClient needs make sign but not found login user";return this.logger.error(e),u(g.SDK_ERROR,e)}try{const r=await(async(e,t)=>{const s=T(e);return await R(s,t)})(s.data,t.secretKey);e.headers||(e.headers={}),e.headers.sign=r}catch(e){const t=`[HttpClient] HttpClient make sign error: ${e.message}`;return this.logger.error(t),u(g.SDK_ERROR,t)}}const r=await this.instance.request({...s,headers:{...e.headers||{}}}),i=r.data;return 0!==i.code?(this.logger.error("[HttpClient]","Business server response error:",r),{ok:!1,code:i.code,msg:i.msg,msg_i18n:i.msg_i18n}):{ok:!0,data:i.data}}catch(e){return this.handleError(e)}}handleError(e){return"ECONNABORTED"===e.code?{ok:!1,code:g.NETWORK_ERROR,msg:e.message||"request timeout"}:{ok:!1,code:g.NETWORK_ERROR,msg:e.message||"network error"}}}class I{listeners=new Map;logger;constructor(e){this.logger=e}on(e,t){this.listeners.has(e)||this.listeners.set(e,new Set),this.listeners.get(e).add(t)}once(e,t){const s=r=>{t(r),this.off(e,s)};this.on(e,s)}off(e,t){this.listeners.has(e)&&(t?this.listeners.get(e).delete(t):this.listeners.delete(e))}emit(e,t){if(this.listeners.has(e))for(const s of this.listeners.get(e))try{s(t)}catch(t){this.logger.error(`[EventCore] handler error on "${String(e)}":`,t)}}clear(){this.listeners.clear()}}var D,A,O,N;!function(e){e.INIT="INIT",e.CONNECTING="CONNECTING",e.CONNECTED="CONNECTED",e.DISCONNECTED="DISCONNECTED",e.CLOSED="CLOSED"}(D||(D={})),function(e){e.OPEN="OPEN",e.ERROR="ERROR",e.CLOSE="CLOSE",e.MESSAGE="MESSAGE",e.STATUS_CHANGE="STATUS_CHANGE"}(A||(A={}));class b extends I{ws;options;status=D.INIT;constructor(e,t){super(t),this.options=e}connect(){if(this.status===D.CONNECTING||this.status===D.CONNECTED)return void this.logger.debug("[CONNECTION]","WebSocket is connecting or connected,current connect status is",`[${this.status}]`);this.logger.debug("[CONNECTION][connect]","WebSocket is connecting"),this.setStatus(D.CONNECTING);const e=new WebSocket(`${this.options.url}?token=${this.options.token}&platform=web`);this.ws=e,e.onopen=()=>{this.logger.debug("[CONNECTION][ws.onopen]","WebSocket is connected"),this.setStatus(D.CONNECTED),this.emit(A.OPEN)},e.onmessage=e=>{this.logger.debug("[CONNECTION][ws.onmessage]","WebSocket received a message",e.data),this.emit(A.MESSAGE,e.data)},e.onerror=e=>{this.logger.error("[CONNECTION][ws.onerror]","WebSocket connect error",e),this.emit(A.ERROR,e)},e.onclose=e=>{this.logger.debug("[CONNECTION][ws.onclose]","WebSocket connect be closed",e),this.setStatus(D.DISCONNECTED),this.emit(A.CLOSE,e)}}close(){this.ws?.close(),this.ws=void 0,this.setStatus(D.CLOSED)}send(e){if(this.status!==D.CONNECTED)throw new Error("WebSocket is not connected");this.ws.send(e)}getStatus(){return this.status}setStatus(e){this.status!==e&&(this.status=e,this.emit(A.STATUS_CHANGE,e))}}class f{connection;pingTimeout;pongTimeout;pingTimer;pongTimer;logger;constructor(e,t,s={}){this.connection=e,this.pingTimeout=s.pingTimeout??3e4,this.pongTimeout=s.pongTimeout??2e4,this.logger=t}ping(e){this.logger.debug("[Heartbeat]","Heartbeat ping"),this.stop(),this.pingTimer=window.setTimeout(()=>{try{this.connection.send(JSON.stringify({type:0})),this.logger.debug("[Heartbeat]","Heartbeat send PING"),this.pong(e)}catch{}},this.pingTimeout)}pong(e){clearTimeout(this.pongTimer),this.pongTimer=window.setTimeout(()=>{e?.(),this.logger.debug("[Heartbeat]","Heartbeat called PONG callback")},this.pongTimeout)}stop(){this.logger.debug("[Heartbeat]","Heartbeat stop"),clearTimeout(this.pingTimer),clearTimeout(this.pongTimer),this.pingTimer=void 0,this.pongTimer=void 0}}class P{connection;baseInterval=1e3;maxAttempts=1/0;attempts=0;timer;enabled=!1;logger;constructor(e,t,s={}){this.logger=t,this.connection=e,s.baseInterval&&(this.baseInterval=s.baseInterval),s.maxAttempts&&(this.maxAttempts=s.maxAttempts),this.bindEvents()}bindEvents(){this.connection.on(A.CLOSE,()=>{this.enabled&&this.scheduleReconnect()}),this.connection.on(A.OPEN,()=>{this.reset()})}start(){this.logger.debug("[Reconnector]","Reconnector start"),this.enabled=!0}stop(){this.logger.debug("[Reconnector]","Reconnector stop"),this.enabled=!1,this.clearTimer()}scheduleReconnect(){if(this.logger.debug("[Reconnector]",`Reconnector scheduleReconnect, attempts: ${this.attempts}, maxAttempts: ${this.maxAttempts}`),this.attempts>=this.maxAttempts)return;this.attempts++;const e=this.baseInterval*Math.min(this.attempts,10);this.clearTimer(),this.timer=window.setTimeout(()=>{this.connection.connect()},e)}reset(){this.logger.debug("[Reconnector]","Reconnector reset"),this.attempts=0,this.clearTimer()}clearTimer(){this.timer&&(clearTimeout(this.timer),this.timer=void 0)}}!function(e){e.OPEN="OPEN",e.ERROR="ERROR",e.CLOSE="CLOSE",e.MESSAGE="MESSAGE",e.STATUS_CHANGE="STATUS_CHANGE",e.KICK_OFF="KICK_OFF"}(O||(O={}));class U extends I{connection;reconnector;heartbeat;constructor(e,t){super(t),this.connection=new b({url:e.wsUrl,token:e.token},t),this.reconnector=new P(this.connection,t),this.heartbeat=new f(this.connection,t),this.bindEvents()}connect(){this.reconnector.start(),this.connection.connect()}disconnect(){this.reconnector.stop(),this.heartbeat.stop(),this.connection.close()}startPing(){this.heartbeat.ping(()=>{this.disconnect();const e=setTimeout(()=>{this.connect(),clearTimeout(e)},1e4)})}bindEvents(){this.connection.on(A.OPEN,()=>{this.emit(O.OPEN),this.startPing()}),this.connection.on(A.CLOSE,e=>{if(e.code===i.KICK_OFF)return this.logger.warn("[IMClient][CLOSE][KICK_OFF]","You has been kicked off"),this.emit(O.KICK_OFF),void this.disconnect();this.emit(O.CLOSE)}),this.connection.on(A.MESSAGE,e=>{this.handleRawMessage(e)}),this.connection.on(A.STATUS_CHANGE,e=>{this.emit(O.STATUS_CHANGE,e)}),this.connection.on(A.ERROR,e=>{this.emit(O.ERROR,e)})}handleRawMessage(e){try{const t=JSON.parse(e);if(t.type===n.PONG_MESSAGE?this.startPing():this.sendAck(t.id),t.type===n.BIG_PACKAGE_PUSH)for(const e of t.content.big_push)this.emit(O.MESSAGE,e);else this.emit(O.MESSAGE,t)}catch(e){this.logger.error("[IMClient][handleRawMessage]","Message raw data json.parse error",e),this.emit(O.ERROR,e)}}sendAck(e){this.connection.send(JSON.stringify({type:1,ids:[e]}))}}!function(e){e.APP_ID="appId",e.TOKEN="token",e.CURRENT_USER="currentUser",e.CURRENT_FEED="currentFeed",e.SDK_READY="sdkReady",e.IS_CONNECTED="isConnected",e.DEVICE_ID="typeximDeviceId",e.BROWSER_FINGERPRINT="typeximBrowserFingerprint",e.TAB_ID="typeximTabId"}(N||(N={}));class y extends I{state={};constructor(e){super(e)}set(e,t){this.logger.debug("[Store] set:",e,t),this.state[e]=t,this.emit("change",{key:e,value:t})}get(e){return this.logger.debug("[Store] get:",e,this.state[e]),this.state[e]}remove(e){this.logger.debug("[Store] remove:",e,this.state[e]),delete this.state[e],this.emit("change",{key:e,value:void 0})}clear(){this.logger.debug("[Store] clear",this.state),this.state={appId:this.state.appId,token:this.state.token,typeximBrowserFingerprint:this.state.typeximBrowserFingerprint},this.emit("clear",void 0)}setWithLocal(e,t){this.logger.debug("[Store] setWithLocal:",e,t),this.set(e,t),localStorage.setItem(e,JSON.stringify(t))}getWithLocal(e){if(this.logger.debug("[Store] getWithLocal:",e,this.state[e]),this.state[e])return this.state[e];const t=localStorage.getItem(e);return t?JSON.parse(t):void 0}removeWithLocal(e){this.logger.debug("[Store] removeWithLocal:",e,this.state[e]),localStorage.removeItem(e),this.remove(e)}setWithSession(e,t){this.logger.debug("[Store] setWithSession:",e,t),this.set(e,t),sessionStorage.setItem(e,JSON.stringify(t))}getWithSession(e){if(this.logger.debug("[Store] getWithSession:",e,this.state[e]),this.state[e])return this.state[e];const t=sessionStorage.getItem(e);return t?JSON.parse(t):void 0}removeWithSession(e){this.logger.debug("[Store] removeWithSession:",e,this.state[e]),sessionStorage.removeItem(e),this.remove(e)}onChange(e){this.on("change",e)}offChange(e){this.off("change",e)}onClear(e){this.on("clear",e)}get appId(){return this.logger.debug("[Store] get appId",this.state.appId),this.state.appId}get ready(){return this.logger.debug("[Store] get ready",this.state.sdkReady),!!this.state.sdkReady}get deviceId(){const e=this.getWithLocal(N.DEVICE_ID);return this.logger.debug("[Store] get deviceId",e),e}get currentUser(){return this.logger.debug("[Store] get currentUser",this.state.currentUser),this.state.currentUser}get currentChatId(){return this.logger.debug("[Store] get currentChatId",this.state.currentFeed?.chat_id),this.state.currentFeed?.chat_id}get currentFeed(){return this.logger.debug("[Store] get currentFeed",this.state.currentFeed),this.state.currentFeed}get sessionId(){return this.logger.debug("[Store] get sessionId",this.state.currentUser?.sessionId),this.state.currentUser?.sessionId}get token(){return this.logger.debug("[Store] get token",this.state.token),this.state.token}get browserFingerprint(){const e=this.getWithLocal(N.BROWSER_FINGERPRINT);return this.logger.debug("[Store] get browserFingerprint",e),e}get tabId(){const e=this.getWithSession(N.TAB_ID);return this.logger.debug("[Store] get tabId",e),e}}class w{version;constructor(){this.version=0}increment(){this.version++}get currentVersion(){return this.version}check(e){return e===this.version}}const M="@typexim/agent-js-sdk_broadcast_channel";class F{config;logger;http;imClient=null;store;events;version;loadFeedAbortController=null;constructor(e,t,s){this.logger=new p,this.store=new y(this.logger),this.events=new I(this.logger),this.store.set(N.APP_ID,e),this.store.set(N.TOKEN,t),this.config=s,this.version=new w,this.http=new C({baseURL:s.httpHost,developer:s.developer},{logger:this.logger,store:this.store}),this.generateTabId(),this.generateBrowserFingerprint(),this.listenBroadcastChannel()}setLogLevel(e){this.logger.setLogLevel(e)}async login(e){try{const t={...e||{}};if(t.userId&&!t.busiToken)return u(g.SDK_ERROR,"Invalid param: userId and busiToken must be provided together");if(!t.userId){const e=this.store.browserFingerprint||await this.generateBrowserFingerprint();t.userId=e}const s=await this.innerRegister(t);if(!s.ok||!s.data)return this.logger.error("[InternalChatSdk] innerRegister failed",s),u(s.code,s.msg,s.msg_i18n);const i=s.data,n=await this.requestDeviceId(),o=await this.innerLogin(i,n,t);if(!o.ok||!o.data)return this.logger.error("[InternalChatSdk] innerLogin failed",o),u(o.code,o.msg,o.msg_i18n);const a=r.get("sessionid");if(!a)throw new Error("Login failed, not found sessionid");const h=o.data||{};return h.sessionId=a,h.secretKey=o.data.key,await Promise.all([this.syncLoginState(h),this.connectWebSocket(a)]),this.notifyOtherTabsLogin(),_({id:h.id,userId:t.userId,name:h.name,avatar:h.avatar,email:h.email})}catch(e){return this.handleException(e)}}innerRegister(e){return this.http.post("/open/user/register",{userID:e.userId,name:e.name,avatar:e.avatar,email:e.email,passWord:e.password,userBuf:e.userBuf,busiToken:e.busiToken})}innerLogin(e,t,s){return this.http.post("/open/user/login",{uid:e,busi_token:s.busiToken,device_id:t})}generateTabId(){const e=this.store.getWithSession(N.TAB_ID);if(e)return e;const t=`${this.store.appId}_${Date.now()}_${Math.random().toString(36).substring(2,15)}`;return this.store.setWithSession(N.TAB_ID,t),t}async generateBrowserFingerprint(){try{const e=this.store.getWithLocal(N.BROWSER_FINGERPRINT);if(e)return this.logger.debug("[ChatSdk] generateBrowserFingerprint success from localstorage",e),e;const t=await s.load(),r=await t.get();return this.logger.debug("[ChatSdk] generateBrowserFingerprint success",r.visitorId),this.store.setWithLocal(N.BROWSER_FINGERPRINT,r.visitorId),r.visitorId}catch(e){this.logger.info("[ChatSdk] FingerprintJS generateBrowserFingerprint Error",e);const t=`${Date.now()}_${Math.random().toString(36).substring(2,15)}`;return this.logger.debug("[ChatSdk] random generateBrowserFingerprint success",t),this.store.setWithLocal(N.BROWSER_FINGERPRINT,t),t}}async loadFeed(){const e=this.version.currentVersion;this.loadFeedAbortController&&this.loadFeedAbortController.abort(),this.loadFeedAbortController=new AbortController;const t=await this.http.get("/feed",{limit:10},{signal:this.loadFeedAbortController.signal}).catch(e=>{this.logger.error("[ChatSdk] loadFeed Error",e)});this.loadFeedAbortController=null;const s=this.version.check(e);if(!t||!s)return;const r=t.data?.feed_list?.find(e=>e.chat_type===a.groupChat);t.ok&&(this.logger.debug("[ChatSdk][FEED_UPDATED] loadFeed success",r),this.store.set(N.CURRENT_FEED,r),this.events.emit(E.FEED_UPDATED,r))}async syncLoginState(e){this.store.set(N.CURRENT_USER,e),this.store.set(N.SDK_READY,!0),await this.loadFeed(),this.events.emit(E.SDK_READY)}syncLogoutState(){this.unlistenBroadcastChannel(),this.store.set(N.CURRENT_USER,void 0),this.store.set(N.SDK_READY,!1),this.store.set(N.CURRENT_FEED,void 0),this.events.emit(E.SDK_NOT_READY)}async requestDeviceId(){const e=this.store.getWithLocal(N.DEVICE_ID);if(e)return this.logger.debug("[ChatSdk] requestDeviceId success from localstorage",e),e;const t=await this.http.post("/device_api/device_id",{platform:"web",hash_str:this.store.browserFingerprint||""}).catch(e=>{this.logger.error("[ChatSdk] requestDeviceId Error",e)});if(t?.ok&&t?.data)return this.logger.debug("[ChatSdk] requestDeviceId success",t.data),this.store.setWithLocal(N.DEVICE_ID,t.data),t.data;if(this.store.browserFingerprint)return this.logger.debug("[ChatSdk] use browserFingerprint as deviceId",this.store.browserFingerprint),this.store.setWithLocal(N.DEVICE_ID,this.store.browserFingerprint),this.store.browserFingerprint;const s=`${Date.now()}_${Math.random().toString(36).substring(2,15)}`;return this.logger.debug("[ChatSdk] random generateDeviceId success",s),this.store.setWithLocal(N.DEVICE_ID,s),s}async logout(){try{if(!this.store.currentUser)return _(null);const e=await this.http.get("/user/logout");return e.ok?(this.syncLogoutState(),this.disconnectWebSocket(),_(null)):u(e.code,e.msg,e.msg_i18n)}catch(e){return this.handleException(e)}}async addGroupMember(e,t){try{if(this.assertReady(),!e)return u(g.SDK_ERROR,"not found chat id");if(!t?.length)return _(null);const s=this.store.currentFeed;if(!s)return u(g.SDK_ERROR,"not found current feed");const r=await this.getChatMembers(s.chat_id,s.chat_member);if(!r.ok)return u(r.code,r.msg,r.msg_i18n);const i=(r.data||[]).map(e=>e.user_id),n=t.filter(e=>!i.includes(e)),o=await this.addMember(n,s.chat_id);return o.ok?_(o.data):u(o.code,o.msg,o.msg_i18n)}catch(e){return this.handleException(e)}}async initialChat(e){try{this.assertReady();const t=this.store.currentFeed;if(!t){const t=await this.createFeed(e.receiverIds);return t.ok&&t.data?(this.store.set(N.CURRENT_FEED,t.data),_(t.data.chat_id)):u(t.code,t.msg,t.msg_i18n)}const s=await this.addGroupMember(t.chat_id,e.receiverIds);return s.ok?_(t.chat_id):s}catch(e){return this.handleException(e)}}async getCurrentFeed(){try{return this.assertReady(),{ok:!0,data:this.store.currentFeed}}catch(e){return this.handleException(e)}}async getMessageList(e){try{this.assertReady();const t=this.store.currentFeed;if(!t)return u(g.SDK_ERROR,"No feed found");const{chat_id:s,first_position:r,last_message_position:i}=t,{positions:n,nextPosition:o,hasMore:a}=(e=>{const t=[];if(e.direction===l.up){let s=e.startPosition??e.maxPosition;for(;t.length<e.limit&&s>=e.minPosition;)t.push(s),s--;const r=s>=e.minPosition;let i;return r&&(i=s),{positions:t,nextPosition:i,hasMore:r}}{let s=e.startPosition??e.minPosition;for(;t.length<e.limit&&s<=e.maxPosition;)t.push(s),s++;const r=s<=e.maxPosition;let i;return r&&(i=s),{positions:t,nextPosition:i,hasMore:r}}})({maxPosition:i,minPosition:r,startPosition:e.messagePosition,limit:e.limit,direction:e.direction??l.up});if(n.length>0){const e=await this.http.post("/message/get_by_position",{chat_position:{[s]:n}});if(e.ok&&e.data?.[s]){return _({hasMore:a,list:e.data[s].reverse().filter(e=>e.message_kind_id!==h.system&&e.operation!==d.recall),nextMessagePosition:o})}return u(e.code,e.msg,e.msg_i18n)}return _({hasMore:!1,list:[]})}catch(e){return this.handleException(e)}}async sendMessage(e){try{this.assertReady();const t=e.messageType;switch(t){case c.text:return this.sendTextMessage(e);case c.image:return this.sendImageMessage(e);case c.video:return this.sendVideoMessage(e);case c.file:return this.sendFileMessage(e);default:return this.logger.warn("Unsupported message type: ",t),u(g.SDK_ERROR,`Unsupported message type: ${t}`)}}catch(e){return this.handleException(e)}}async sendTextMessage(e){return this.http.post("/message/send_text",{chat_id:e.chatId,client_msg_id:e.clientMsgId,text:e.text.trim()},{needSign:!0})}async sendImageMessage(e){return this.http.post("/message/send_image",{chat_id:e.chatId,client_msg_id:e.clientMsgId,object_url:e.objectUrl,width:e.width,height:e.height},{needSign:!0})}async sendVideoMessage(e){return this.http.post("/message/send_video",{chat_id:e.chatId,client_msg_id:e.clientMsgId,video_url:e.objectUrl,duration_second:e.duration,image_url:e.coverUrl,width:e.width,height:e.height},{needSign:!0})}async sendFileMessage(e){return this.http.post("/message/send_file",{chat_id:e.chatId,client_msg_id:e.clientMsgId,object_url:e.objectUrl,file_name:e.fileName,file_size:e.fileSize},{needSign:!0})}async uploadFile(e){const{chatId:t,fileContent:s,fileFormat:r,fileName:i,fileType:n,onUploadProgress:o}=e,a=new FormData;return a.append("file_content",s),a.append("file_type",n),a.append("file_name",i),a.append("file_format",r),a.append("chat_id",t),this.http.post("/chat/upload",a,{needSign:!1,ignoreDeveloper:!0,onUploadProgress:o,headers:{"Content-Type":"multipart/form-data"}})}async sendMessageReadReceipt(e){try{return this.assertReady(),e.messageIds?.length?this.http.post("/message/read",{chat_id:e.chatId,message_ids:e.messageIds},{needSign:!0}):_(null)}catch(e){return this.handleException(e)}}async markAllMessagesAsRead(e){const t=this.store.currentFeed?.unread_message_ids||[];return this.sendMessageReadReceipt({chatId:e,messageIds:t})}async recallMessage(e){try{return this.assertReady(),e.messageIds.length?this.http.post("/message/remove",{chat_id:e.chatId,message_ids:e.messageIds,two_way:1},{needSign:!0}):_(null)}catch(e){return this.handleException(e)}}async createFeed(e){return await this.http.post("/chat/group",{receiver_ids:e,group_type:0,name:`User ${this.store.currentUser?.name||this.store.currentUser?.id}`},{needSign:!0})}async getChatMembers(e,t){return this.http.post("/chat/chatter_info",JSON.stringify({chatters:{[e]:t}}))}async addMember(e,t){return t?e.length?this.http.post("/chat/group/add_member",{user_ids:e,chat_id:t},{needSign:!0}):_(null):u(g.SDK_ERROR,"not found chat id")}handlePushMessage(e){switch(this.logger.debug("handlePushMessage",e),e.type){case n.CREATE_FEED:case n.UPDATE_FEED:this.handleFeedUpdate(e);break;case n.ADD_MESSAGE:this.handleAddMessage(e);break;case n.UPDATE_MESSAGE:this.handleUpdateMessage(e);break;case n.READ_MESSAGE:this.handleReadMessage(e);break;case n.KICK_OUT_DEVICE:this.handleKickOut()}}handleFeedUpdate(e){this.store.set(N.CURRENT_FEED,e.content),this.events.emit(E.FEED_UPDATED,e.content)}async handleAddMessage(e){e.content.chat_id===this.store.currentChatId&&(await this.loadFeed(),this.events.emit(E.MESSAGE_RECEIVED,e.content))}async handleUpdateMessage(e){e.content.chat_id===this.store.currentChatId&&(await this.loadFeed(),this.events.emit(E.MESSAGE_UPDATED,e.content))}async handleReadMessage(e){e.content.chat_id===this.store.currentChatId&&(await this.loadFeed(),this.events.emit(E.MESSAGE_RECEIPT_RECEIVED,{chatId:e.content.chat_id,messageIds:e.content.message_ids,readerUserIds:e.content.reader_ids}))}handleKickOut(){this.syncLogoutState(),this.disconnectWebSocket(),this.events.emit(E.SDK_KICKOUT)}on(e,t){return this.events.on(e,t)}once(e,t){return this.events.once(e,t)}off(e,t){return this.events.off(e,t)}get currentUserId(){return this.logger.debug("[InternalChatSdk] get currentUserId==>",this.store.currentUser),this.store.currentUser?.id}get currentChatId(){return this.logger.debug("[InternalChatSdk] get currentChatId==>",this.store.currentChatId),this.store.currentChatId}get isReady(){return this.logger.debug("[InternalChatSdk] get isReady==>",this.store.ready),this.store.ready}listenBroadcastChannel(){new BroadcastChannel(M).onmessage=e=>{const t=this.store.appId,s=this.store.tabId;e.data.type===o.KICK_OUT&&e.data.appId===t&&e.data.tabId!==s&&(this.logger.debug("[BroadcastChannel] message: kick out",{appId:t,sourceTabId:e.data.tabId,currentTabId:s}),this.handleKickOut())}}unlistenBroadcastChannel(){new BroadcastChannel(M).close()}notifyOtherTabsLogin(){new BroadcastChannel(M).postMessage({type:o.KICK_OUT,appId:this.store.appId,tabId:this.store.tabId})}async connectWebSocket(e){if(!e)throw Error("connect websocket error, not found login user token");this.imClient=new U({token:e,wsUrl:`${this.config.websocketHost}/ws`},this.logger),this.imClient.on(O.OPEN,()=>{this.store.set(N.IS_CONNECTED,!0)}),this.imClient.on(O.KICK_OFF,()=>{this.store.set(N.IS_CONNECTED,!1)}),this.imClient.on(O.CLOSE,()=>{this.store.set(N.IS_CONNECTED,!1)}),this.imClient.on(O.MESSAGE,e=>{this.handlePushMessage(e)}),this.imClient.connect()}disconnectWebSocket(){this.imClient&&(this.imClient.disconnect(),this.imClient=null)}assertReady(){if(!this.store.ready)throw{code:g.SDK_ERROR,msg:"sdk not ready"}}handleException(e){return this.logger.error("[ChatSDK Error]",e),{ok:!1,code:e.code||g.SDK_ERROR,msg:e.msg||e.message||"sdk error"}}}const L=new Map;function v(e){return{setLogLevel(t){e.setLogLevel(t)},login:t=>e.login(t),logout:()=>e.logout(),initialChat:t=>e.initialChat(t),addGroupMember:(t,s)=>e.addGroupMember(t,s),getCurrentFeed:()=>e.getCurrentFeed(),getMessageList:t=>e.getMessageList(t),uploadFile:t=>e.uploadFile(t),sendMessage:t=>e.sendMessage(t),sendMessageReadReceipt:t=>e.sendMessageReadReceipt(t),markAllMessagesAsRead:t=>e.markAllMessagesAsRead(t),recallMessage:t=>e.recallMessage(t),get currentUserId(){return e.currentUserId},get currentChatId(){return e.currentChatId},get isReady(){return e.isReady},on:(t,s)=>e.on(t,s),once:(t,s)=>e.once(t,s),off:(t,s)=>e.off(t,s)}}var G={create:function(e,t,s){if(L.has(e))return v(L.get(e));const r=new F(e,t,s);return L.set(e,r),v(r)}};export{g as ChatSdkErrorCode,E as ChatSdkEvent,a as ChatType,h as MessageKind,d as MessageOperation,c as MessageType,l as RequestDirection,G as default};
|
|
1
|
+
import e from"crypto-js";import t from"axios";import s from"@fingerprintjs/fingerprintjs";import r from"js-cookie";var i,n,o,a,h,c,d,g,E,l;function u(e,t,s){return{ok:!1,code:e||g.SDK_ERROR,msg:t||"sdk error",msg_i18n:s}}function _(e){return{ok:!0,data:e}}!function(e){e[e.KICK_OFF=4001]="KICK_OFF"}(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.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"}(n||(n={})),function(e){e[e.KICK_OUT=0]="KICK_OUT"}(o||(o={})),function(e){e[e.singleChat=1]="singleChat",e[e.groupChat=2]="groupChat"}(a||(a={})),function(e){e[e.normal=0]="normal",e[e.system=1]="system"}(h||(h={})),function(e){e[e.text=0]="text",e[e.image=1]="image",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.contact=9]="contact",e[e.communication=10]="communication",e[e.mixedImageText=11]="mixedImageText",e[e.luckyGift=14]="luckyGift",e[e.fileGroup=15]="fileGroup",e[e.cardMsg=16]="cardMsg"}(c||(c={})),function(e){e[e.normal=0]="normal",e[e.recall=1]="recall"}(d||(d={})),function(e){e[e.NETWORK_ERROR=-1e4]="NETWORK_ERROR",e[e.SDK_ERROR=-10001]="SDK_ERROR"}(g||(g={})),function(e){e.SDK_READY="SDK_READY",e.SDK_NOT_READY="SDK_NOT_READY",e.SDK_KICKOUT="SDK_KICKOUT",e.FEED_UPDATED="FEED_UPDATED",e.MESSAGE_RECEIVED="MESSAGE_RECEIVED",e.MESSAGE_UPDATED="MESSAGE_UPDATED",e.MESSAGE_RECEIPT_RECEIVED="MESSAGE_RECEIPT_RECEIVED"}(E||(E={})),function(e){e[e.up=0]="up",e[e.down=1]="down"}(l||(l={}));const S="[TYPEX_AGENT_JS_SDK]";class m{level=0;setLogLevel(e){this.level=e}getLogLevel(){return this.level}shouldPrint(e){return e>=this.level}debug(...e){this.shouldPrint(0)&&console.debug(`${S}[DEBUG]`,...e)}info(...e){this.shouldPrint(0)&&console.info(`${S}[INFO]`,...e)}warn(...e){this.shouldPrint(1)&&console.warn(`${S}[WARN]`,...e)}error(...e){this.shouldPrint(2)&&console.error(`${S}[ERROR]`,...e)}}function p(e){return(new TextEncoder).encode(e).buffer}async function T(t,s){return window.crypto&&window.crypto.subtle?await async function(e,t){const s=p(t),r=p(e),i=await crypto.subtle.importKey("raw",s,{name:"HMAC",hash:{name:"SHA-256"}},!1,["sign"]),n=await crypto.subtle.sign("HMAC",i,r);return Array.from(new Uint8Array(n)).map(e=>e.toString(16).padStart(2,"0")).join("")}(t,s):function(t,s){const r=e.HmacSHA256(t,s);return e.enc.Hex.stringify(r)}(t,s)}const R=e=>{if(null==e)return"";if("object"!=typeof e||Array.isArray(e)){if(Array.isArray(e)){let t="";for(const s of e)t+=R(s);return t}return"string"==typeof e?e:String(e)}{const t=Object.keys(e).sort();let s="";for(const r of t)s+=R(e[r]);return s}};class C{instance;developer;logger;store;constructor(e,s){this.logger=s.logger,this.store=s.store,this.developer=e.developer;const r=e.baseURL.replace(/\/$/,"");this.instance=t.create({baseURL:r,headers:{...e.defaultHeaders??{}},timeout:e.timeout??3e4}),this.setupInterceptors()}setupInterceptors(){this.instance.interceptors.request.use(e=>(e.headers=e.headers||{},e.headers["Content-Type"]||(e.headers["Content-Type"]="application/json"),e.headers.Platform="web",e.headers.AppID=this.store.appId,e.url?.startsWith("/open")&&(e.headers.Authorization=`Bearer ${this.store.token}`),this.developer&&!e.ignoreDeveloper&&(e.headers["x-developer"]=this.developer),e))}async get(e,t={},s={}){return this.request({url:e,method:"GET",params:t,...s})}async post(e,t,s={}){return this.request({url:e,method:"POST",data:t,...s})}async request(e){try{const{needSign:t,...s}=e;if(t&&"POST"===s.method?.toUpperCase()&&s.data){const t=this.store.currentUser;if(!t){const e="[HttpClient] HttpClient needs make sign but not found login user";return this.logger.error(e),u(g.SDK_ERROR,e)}try{const r=await(async(e,t)=>{const s=R(e);return await T(s,t)})(s.data,t.secretKey);e.headers||(e.headers={}),e.headers.sign=r}catch(e){const t=`[HttpClient] HttpClient make sign error: ${e.message}`;return this.logger.error(t),u(g.SDK_ERROR,t)}}const r=await this.instance.request({...s,headers:{...e.headers||{}}}),i=r.data;return 0!==i.code?(this.logger.error("[HttpClient]","Business server response error:",r),{ok:!1,code:i.code,msg:i.msg,msg_i18n:i.msg_i18n}):{ok:!0,data:i.data}}catch(e){return this.handleError(e)}}handleError(e){return"ECONNABORTED"===e.code?{ok:!1,code:g.NETWORK_ERROR,msg:e.message||"request timeout"}:{ok:!1,code:g.NETWORK_ERROR,msg:e.message||"network error"}}}class I{listeners=new Map;logger;constructor(e){this.logger=e}on(e,t){this.listeners.has(e)||this.listeners.set(e,new Set),this.listeners.get(e).add(t)}once(e,t){const s=r=>{t(r),this.off(e,s)};this.on(e,s)}off(e,t){this.listeners.has(e)&&(t?this.listeners.get(e).delete(t):this.listeners.delete(e))}emit(e,t){if(this.listeners.has(e))for(const s of this.listeners.get(e))try{s(t)}catch(t){this.logger.error(`[EventCore] handler error on "${String(e)}":`,t)}}clear(){this.listeners.clear()}}var D,A,O,N;!function(e){e.INIT="INIT",e.CONNECTING="CONNECTING",e.CONNECTED="CONNECTED",e.DISCONNECTED="DISCONNECTED",e.CLOSED="CLOSED"}(D||(D={})),function(e){e.OPEN="OPEN",e.ERROR="ERROR",e.CLOSE="CLOSE",e.MESSAGE="MESSAGE",e.STATUS_CHANGE="STATUS_CHANGE"}(A||(A={}));class b extends I{ws;options;status=D.INIT;constructor(e,t){super(t),this.options=e}connect(){if(this.status===D.CONNECTING||this.status===D.CONNECTED)return void this.logger.debug("[CONNECTION]","WebSocket is connecting or connected,current connect status is",`[${this.status}]`);this.logger.debug("[CONNECTION][connect]","WebSocket is connecting"),this.setStatus(D.CONNECTING);const e=new WebSocket(`${this.options.url}?token=${this.options.token}&platform=web`);this.ws=e,e.onopen=()=>{this.logger.debug("[CONNECTION][ws.onopen]","WebSocket is connected"),this.setStatus(D.CONNECTED),this.emit(A.OPEN)},e.onmessage=e=>{this.logger.debug("[CONNECTION][ws.onmessage]","WebSocket received a message",e.data),this.emit(A.MESSAGE,e.data)},e.onerror=e=>{this.logger.error("[CONNECTION][ws.onerror]","WebSocket connect error",e),this.emit(A.ERROR,e)},e.onclose=e=>{this.logger.debug("[CONNECTION][ws.onclose]","WebSocket connect be closed",e),this.setStatus(D.DISCONNECTED),this.emit(A.CLOSE,e)}}close(){this.ws?.close(),this.ws=void 0,this.setStatus(D.CLOSED)}send(e){if(this.status!==D.CONNECTED)throw new Error("WebSocket is not connected");this.ws.send(e)}getStatus(){return this.status}setStatus(e){this.status!==e&&(this.status=e,this.emit(A.STATUS_CHANGE,e))}}class f{connection;pingTimeout;pongTimeout;pingTimer;pongTimer;logger;constructor(e,t,s={}){this.connection=e,this.pingTimeout=s.pingTimeout??3e4,this.pongTimeout=s.pongTimeout??2e4,this.logger=t}ping(e){this.logger.debug("[Heartbeat]","Heartbeat ping"),this.stop(),this.pingTimer=window.setTimeout(()=>{try{this.connection.send(JSON.stringify({type:0})),this.logger.debug("[Heartbeat]","Heartbeat send PING"),this.pong(e)}catch{}},this.pingTimeout)}pong(e){clearTimeout(this.pongTimer),this.pongTimer=window.setTimeout(()=>{e?.(),this.logger.debug("[Heartbeat]","PING timeout, called PING/PONG callback")},this.pongTimeout)}stop(){this.logger.debug("[Heartbeat]","Heartbeat stop"),clearTimeout(this.pingTimer),clearTimeout(this.pongTimer),this.pingTimer=void 0,this.pongTimer=void 0}}class P{connection;baseInterval=1e3;maxAttempts=1/0;attempts=0;timer;enabled=!1;logger;constructor(e,t,s={}){this.logger=t,this.connection=e,s.baseInterval&&(this.baseInterval=s.baseInterval),s.maxAttempts&&(this.maxAttempts=s.maxAttempts),this.bindEvents()}bindEvents(){this.connection.on(A.CLOSE,()=>{this.enabled&&this.scheduleReconnect()}),this.connection.on(A.OPEN,()=>{this.reset()})}start(){this.logger.debug("[Reconnector]","Reconnector start"),this.enabled=!0}stop(){this.logger.debug("[Reconnector]","Reconnector stop"),this.enabled=!1,this.clearTimer()}scheduleReconnect(){if(this.logger.debug("[Reconnector]",`Reconnector scheduleReconnect, attempts: ${this.attempts}, maxAttempts: ${this.maxAttempts}`),this.attempts>=this.maxAttempts)return;this.attempts++;const e=this.baseInterval*Math.min(this.attempts,10);this.clearTimer(),this.timer=window.setTimeout(()=>{this.connection.connect()},e)}reset(){this.logger.debug("[Reconnector]","Reconnector reset"),this.attempts=0,this.clearTimer()}clearTimer(){this.timer&&(clearTimeout(this.timer),this.timer=void 0)}}!function(e){e.OPEN="OPEN",e.ERROR="ERROR",e.CLOSE="CLOSE",e.MESSAGE="MESSAGE",e.STATUS_CHANGE="STATUS_CHANGE",e.KICK_OFF="KICK_OFF"}(O||(O={}));class U extends I{connection;reconnector;heartbeat;pongTimeoutCount=0;constructor(e,t){super(t),this.connection=new b({url:e.wsUrl,token:e.token},t),this.reconnector=new P(this.connection,t),this.heartbeat=new f(this.connection,t),this.bindEvents()}connect(){this.reconnector.start(),this.connection.connect()}disconnect(){this.reconnector.stop(),this.heartbeat.stop(),this.connection.close()}startPing(){this.heartbeat.ping(()=>{if(this.logger.warn("[IMClient][Heartbeat]","PONG timeout, current pong timeout count: ",this.pongTimeoutCount),this.pongTimeoutCount++,this.pongTimeoutCount>=5){this.disconnect();const e=setTimeout(()=>{this.connect(),clearTimeout(e)},1e4);return}this.startPing()})}bindEvents(){this.connection.on(A.OPEN,()=>{this.emit(O.OPEN),this.startPing()}),this.connection.on(A.CLOSE,e=>{if(e.code===i.KICK_OFF)return this.logger.warn("[IMClient][CLOSE][KICK_OFF]","You has been kicked off"),this.emit(O.KICK_OFF),void this.disconnect();this.emit(O.CLOSE)}),this.connection.on(A.MESSAGE,e=>{this.handleRawMessage(e)}),this.connection.on(A.STATUS_CHANGE,e=>{this.emit(O.STATUS_CHANGE,e)}),this.connection.on(A.ERROR,e=>{this.emit(O.ERROR,e)})}handleRawMessage(e){try{const t=JSON.parse(e);if(t.type===n.PONG_MESSAGE?this.startPing():this.sendAck(t.id),t.type===n.BIG_PACKAGE_PUSH)for(const e of t.content.big_push)this.emit(O.MESSAGE,e);else this.emit(O.MESSAGE,t)}catch(e){this.logger.error("[IMClient][handleRawMessage]","Message raw data json.parse error",e),this.emit(O.ERROR,e)}}sendAck(e){this.connection.send(JSON.stringify({type:1,ids:[e]}))}}!function(e){e.APP_ID="appId",e.TOKEN="token",e.CURRENT_USER="currentUser",e.CURRENT_FEED="currentFeed",e.SDK_READY="sdkReady",e.IS_CONNECTED="isConnected",e.DEVICE_ID="typeximDeviceId",e.BROWSER_FINGERPRINT="typeximBrowserFingerprint",e.TAB_ID="typeximTabId"}(N||(N={}));class y extends I{state={};constructor(e){super(e)}set(e,t){this.logger.debug("[Store] set:",e,t),this.state[e]=t,this.emit("change",{key:e,value:t})}get(e){return this.logger.debug("[Store] get:",e,this.state[e]),this.state[e]}remove(e){this.logger.debug("[Store] remove:",e,this.state[e]),delete this.state[e],this.emit("change",{key:e,value:void 0})}clear(){this.logger.debug("[Store] clear",this.state),this.state={appId:this.state.appId,token:this.state.token,typeximBrowserFingerprint:this.state.typeximBrowserFingerprint},this.emit("clear",void 0)}setWithLocal(e,t){this.logger.debug("[Store] setWithLocal:",e,t),this.set(e,t),localStorage.setItem(e,JSON.stringify(t))}getWithLocal(e){if(this.logger.debug("[Store] getWithLocal:",e,this.state[e]),this.state[e])return this.state[e];const t=localStorage.getItem(e);return t?JSON.parse(t):void 0}removeWithLocal(e){this.logger.debug("[Store] removeWithLocal:",e,this.state[e]),localStorage.removeItem(e),this.remove(e)}setWithSession(e,t){this.logger.debug("[Store] setWithSession:",e,t),this.set(e,t),sessionStorage.setItem(e,JSON.stringify(t))}getWithSession(e){if(this.logger.debug("[Store] getWithSession:",e,this.state[e]),this.state[e])return this.state[e];const t=sessionStorage.getItem(e);return t?JSON.parse(t):void 0}removeWithSession(e){this.logger.debug("[Store] removeWithSession:",e,this.state[e]),sessionStorage.removeItem(e),this.remove(e)}onChange(e){this.on("change",e)}offChange(e){this.off("change",e)}onClear(e){this.on("clear",e)}get appId(){return this.logger.debug("[Store] get appId",this.state.appId),this.state.appId}get ready(){return this.logger.debug("[Store] get ready",this.state.sdkReady),!!this.state.sdkReady}get deviceId(){const e=this.getWithLocal(N.DEVICE_ID);return this.logger.debug("[Store] get deviceId",e),e}get currentUser(){return this.logger.debug("[Store] get currentUser",this.state.currentUser),this.state.currentUser}get currentChatId(){return this.logger.debug("[Store] get currentChatId",this.state.currentFeed?.chat_id),this.state.currentFeed?.chat_id}get currentFeed(){return this.logger.debug("[Store] get currentFeed",this.state.currentFeed),this.state.currentFeed}get sessionId(){return this.logger.debug("[Store] get sessionId",this.state.currentUser?.sessionId),this.state.currentUser?.sessionId}get token(){return this.logger.debug("[Store] get token",this.state.token),this.state.token}get browserFingerprint(){const e=this.getWithLocal(N.BROWSER_FINGERPRINT);return this.logger.debug("[Store] get browserFingerprint",e),e}get tabId(){const e=this.getWithSession(N.TAB_ID);return this.logger.debug("[Store] get tabId",e),e}}class w{version;constructor(){this.version=0}increment(){this.version++}get currentVersion(){return this.version}check(e){return e===this.version}}const M="@typexim/agent-js-sdk_broadcast_channel";class F{config;logger;http;imClient=null;store;events;version;loadFeedAbortController=null;constructor(e,t,s){this.logger=new m,this.store=new y(this.logger),this.events=new I(this.logger),this.store.set(N.APP_ID,e),this.store.set(N.TOKEN,t),this.config=s,this.version=new w,this.http=new C({baseURL:s.httpHost,developer:s.developer},{logger:this.logger,store:this.store}),this.generateTabId(),this.generateBrowserFingerprint(),this.listenBroadcastChannel()}setLogLevel(e){this.logger.setLogLevel(e)}async login(e){try{const t={...e||{}};if(t.userId&&!t.busiToken)return u(g.SDK_ERROR,"Invalid param: userId and busiToken must be provided together");if(!t.userId){const e=this.store.browserFingerprint||await this.generateBrowserFingerprint();t.userId=e}const s=await this.innerRegister(t);if(!s.ok||!s.data)return this.logger.error("[InternalChatSdk] innerRegister failed",s),u(s.code,s.msg,s.msg_i18n);const i=s.data,n=await this.requestDeviceId(),o=await this.innerLogin(i,n,t);if(!o.ok||!o.data)return this.logger.error("[InternalChatSdk] innerLogin failed",o),u(o.code,o.msg,o.msg_i18n);const a=r.get("sessionid");if(!a)throw new Error("Login failed, not found sessionid");const h=o.data||{};return h.sessionId=a,h.secretKey=o.data.key,await Promise.all([this.syncLoginState(h),this.connectWebSocket(a)]),this.notifyOtherTabsLogin(),_({id:h.id,userId:t.userId,name:h.name,avatar:h.avatar,email:h.email})}catch(e){return this.handleException(e)}}innerRegister(e){return this.http.post("/open/user/register",{userID:e.userId,name:e.name,avatar:e.avatar,email:e.email,passWord:e.password,userBuf:e.userBuf,busiToken:e.busiToken})}innerLogin(e,t,s){return this.http.post("/open/user/login",{uid:e,busi_token:s.busiToken,device_id:t})}generateTabId(){const e=this.store.getWithSession(N.TAB_ID);if(e)return e;const t=`${this.store.appId}_${Date.now()}_${Math.random().toString(36).substring(2,15)}`;return this.store.setWithSession(N.TAB_ID,t),t}async generateBrowserFingerprint(){try{const e=this.store.getWithLocal(N.BROWSER_FINGERPRINT);if(e)return this.logger.debug("[ChatSdk] generateBrowserFingerprint success from localstorage",e),e;const t=await s.load(),r=await t.get();return this.logger.debug("[ChatSdk] generateBrowserFingerprint success",r.visitorId),this.store.setWithLocal(N.BROWSER_FINGERPRINT,r.visitorId),r.visitorId}catch(e){this.logger.info("[ChatSdk] FingerprintJS generateBrowserFingerprint Error",e);const t=`${Date.now()}_${Math.random().toString(36).substring(2,15)}`;return this.logger.debug("[ChatSdk] random generateBrowserFingerprint success",t),this.store.setWithLocal(N.BROWSER_FINGERPRINT,t),t}}async loadFeed(){const e=this.version.currentVersion;this.loadFeedAbortController&&this.loadFeedAbortController.abort(),this.loadFeedAbortController=new AbortController;const t=await this.http.get("/feed",{limit:10},{signal:this.loadFeedAbortController.signal}).catch(e=>{this.logger.error("[ChatSdk] loadFeed Error",e)});this.loadFeedAbortController=null;const s=this.version.check(e);if(!t||!s)return;const r=t.data?.feed_list?.find(e=>e.chat_type===a.groupChat);t.ok&&(this.logger.debug("[ChatSdk][FEED_UPDATED] loadFeed success",r),this.store.set(N.CURRENT_FEED,r),this.events.emit(E.FEED_UPDATED,r))}async syncLoginState(e){this.store.set(N.CURRENT_USER,e),this.store.set(N.SDK_READY,!0),await this.loadFeed(),this.events.emit(E.SDK_READY)}syncLogoutState(){this.unlistenBroadcastChannel(),this.store.set(N.CURRENT_USER,void 0),this.store.set(N.SDK_READY,!1),this.store.set(N.CURRENT_FEED,void 0),this.events.emit(E.SDK_NOT_READY)}async requestDeviceId(){const e=this.store.getWithLocal(N.DEVICE_ID);if(e)return this.logger.debug("[ChatSdk] requestDeviceId success from localstorage",e),e;const t=await this.http.post("/device_api/device_id",{platform:"web",hash_str:this.store.browserFingerprint||""}).catch(e=>{this.logger.error("[ChatSdk] requestDeviceId Error",e)});if(t?.ok&&t?.data)return this.logger.debug("[ChatSdk] requestDeviceId success",t.data),this.store.setWithLocal(N.DEVICE_ID,t.data),t.data;if(this.store.browserFingerprint)return this.logger.debug("[ChatSdk] use browserFingerprint as deviceId",this.store.browserFingerprint),this.store.setWithLocal(N.DEVICE_ID,this.store.browserFingerprint),this.store.browserFingerprint;const s=`${Date.now()}_${Math.random().toString(36).substring(2,15)}`;return this.logger.debug("[ChatSdk] random generateDeviceId success",s),this.store.setWithLocal(N.DEVICE_ID,s),s}async logout(){try{if(!this.store.currentUser)return _(null);const e=await this.http.get("/user/logout");return e.ok?(this.syncLogoutState(),this.disconnectWebSocket(),_(null)):u(e.code,e.msg,e.msg_i18n)}catch(e){return this.handleException(e)}}async addGroupMember(e,t){try{if(this.assertReady(),!e)return u(g.SDK_ERROR,"not found chat id");if(!t?.length)return _(null);const s=this.store.currentFeed;if(!s)return u(g.SDK_ERROR,"not found current feed");const r=await this.getChatMembers(s.chat_id,s.chat_member);if(!r.ok)return u(r.code,r.msg,r.msg_i18n);const i=(r.data||[]).map(e=>e.user_id),n=t.filter(e=>!i.includes(e)),o=await this.addMember(n,s.chat_id);return o.ok?_(o.data):u(o.code,o.msg,o.msg_i18n)}catch(e){return this.handleException(e)}}async initialChat(e){try{this.assertReady();const t=this.store.currentFeed;if(!t){const t=await this.createFeed(e.receiverIds);return t.ok&&t.data?(this.store.set(N.CURRENT_FEED,t.data),_(t.data.chat_id)):u(t.code,t.msg,t.msg_i18n)}const s=await this.addGroupMember(t.chat_id,e.receiverIds);return s.ok?_(t.chat_id):s}catch(e){return this.handleException(e)}}async getCurrentFeed(){try{return this.assertReady(),{ok:!0,data:this.store.currentFeed}}catch(e){return this.handleException(e)}}async getMessageList(e){try{this.assertReady();const t=this.store.currentFeed;if(!t)return u(g.SDK_ERROR,"No feed found");const{chat_id:s,first_position:r,last_message_position:i}=t,{positions:n,nextPosition:o,hasMore:a}=(e=>{const t=[];if(e.direction===l.up){let s=e.startPosition??e.maxPosition;for(;t.length<e.limit&&s>=e.minPosition;)t.push(s),s--;const r=s>=e.minPosition;let i;return r&&(i=s),{positions:t,nextPosition:i,hasMore:r}}{let s=e.startPosition??e.minPosition;for(;t.length<e.limit&&s<=e.maxPosition;)t.push(s),s++;const r=s<=e.maxPosition;let i;return r&&(i=s),{positions:t,nextPosition:i,hasMore:r}}})({maxPosition:i,minPosition:r,startPosition:e.messagePosition,limit:e.limit,direction:e.direction??l.up});if(n.length>0){const e=await this.http.post("/message/get_by_position",{chat_position:{[s]:n}});if(e.ok&&e.data?.[s]){return _({hasMore:a,list:e.data[s].reverse().filter(e=>e.message_kind_id!==h.system&&e.operation!==d.recall),nextMessagePosition:o})}return u(e.code,e.msg,e.msg_i18n)}return _({hasMore:!1,list:[]})}catch(e){return this.handleException(e)}}async sendMessage(e){try{this.assertReady();const t=e.messageType;switch(t){case c.text:return this.sendTextMessage(e);case c.image:return this.sendImageMessage(e);case c.video:return this.sendVideoMessage(e);case c.file:return this.sendFileMessage(e);default:return this.logger.warn("Unsupported message type: ",t),u(g.SDK_ERROR,`Unsupported message type: ${t}`)}}catch(e){return this.handleException(e)}}async sendTextMessage(e){return this.http.post("/message/send_text",{chat_id:e.chatId,client_msg_id:e.clientMsgId,text:e.text.trim()},{needSign:!0})}async sendImageMessage(e){return this.http.post("/message/send_image",{chat_id:e.chatId,client_msg_id:e.clientMsgId,object_url:e.objectUrl,width:e.width,height:e.height},{needSign:!0})}async sendVideoMessage(e){return this.http.post("/message/send_video",{chat_id:e.chatId,client_msg_id:e.clientMsgId,video_url:e.objectUrl,duration_second:e.duration,image_url:e.coverUrl,width:e.width,height:e.height},{needSign:!0})}async sendFileMessage(e){return this.http.post("/message/send_file",{chat_id:e.chatId,client_msg_id:e.clientMsgId,object_url:e.objectUrl,file_name:e.fileName,file_size:e.fileSize},{needSign:!0})}async uploadFile(e){const{chatId:t,fileContent:s,fileFormat:r,fileName:i,fileType:n,onUploadProgress:o}=e,a=new FormData;return a.append("file_content",s),a.append("file_type",n),a.append("file_name",i),a.append("file_format",r),a.append("chat_id",t),this.http.post("/chat/upload",a,{needSign:!1,ignoreDeveloper:!0,onUploadProgress:o,headers:{"Content-Type":"multipart/form-data"}})}async sendMessageReadReceipt(e){try{return this.assertReady(),e.messageIds?.length?this.http.post("/message/read",{chat_id:e.chatId,message_ids:e.messageIds},{needSign:!0}):_(null)}catch(e){return this.handleException(e)}}async markAllMessagesAsRead(e){const t=this.store.currentFeed?.unread_message_ids||[];return this.sendMessageReadReceipt({chatId:e,messageIds:t})}async recallMessage(e){try{return this.assertReady(),e.messageIds.length?this.http.post("/message/remove",{chat_id:e.chatId,message_ids:e.messageIds,two_way:1},{needSign:!0}):_(null)}catch(e){return this.handleException(e)}}async createFeed(e){return await this.http.post("/chat/group",{receiver_ids:e,group_type:0,name:`User ${this.store.currentUser?.name||this.store.currentUser?.id}`},{needSign:!0})}async getChatMembers(e,t){return this.http.post("/chat/chatter_info",JSON.stringify({chatters:{[e]:t}}))}async addMember(e,t){return t?e.length?this.http.post("/chat/group/add_member",{user_ids:e,chat_id:t},{needSign:!0}):_(null):u(g.SDK_ERROR,"not found chat id")}handlePushMessage(e){switch(this.logger.debug("handlePushMessage",e),e.type){case n.CREATE_FEED:case n.UPDATE_FEED:this.handleFeedUpdate(e);break;case n.ADD_MESSAGE:this.handleAddMessage(e);break;case n.UPDATE_MESSAGE:this.handleUpdateMessage(e);break;case n.READ_MESSAGE:this.handleReadMessage(e);break;case n.KICK_OUT_DEVICE:this.handleKickOut()}}handleFeedUpdate(e){this.store.set(N.CURRENT_FEED,e.content),this.events.emit(E.FEED_UPDATED,e.content)}async handleAddMessage(e){e.content.chat_id===this.store.currentChatId&&(await this.loadFeed(),this.events.emit(E.MESSAGE_RECEIVED,e.content))}async handleUpdateMessage(e){e.content.chat_id===this.store.currentChatId&&(await this.loadFeed(),this.events.emit(E.MESSAGE_UPDATED,e.content))}async handleReadMessage(e){e.content.chat_id===this.store.currentChatId&&(await this.loadFeed(),this.events.emit(E.MESSAGE_RECEIPT_RECEIVED,{chatId:e.content.chat_id,messageIds:e.content.message_ids,readerUserIds:e.content.reader_ids}))}handleKickOut(){this.syncLogoutState(),this.disconnectWebSocket(),this.events.emit(E.SDK_KICKOUT)}on(e,t){return this.events.on(e,t)}once(e,t){return this.events.once(e,t)}off(e,t){return this.events.off(e,t)}get currentUserId(){return this.logger.debug("[InternalChatSdk] get currentUserId==>",this.store.currentUser),this.store.currentUser?.id}get currentChatId(){return this.logger.debug("[InternalChatSdk] get currentChatId==>",this.store.currentChatId),this.store.currentChatId}get isReady(){return this.logger.debug("[InternalChatSdk] get isReady==>",this.store.ready),this.store.ready}listenBroadcastChannel(){new BroadcastChannel(M).onmessage=e=>{const t=this.store.appId,s=this.store.tabId;e.data.type===o.KICK_OUT&&e.data.appId===t&&e.data.tabId!==s&&(this.logger.debug("[BroadcastChannel] message: kick out",{appId:t,sourceTabId:e.data.tabId,currentTabId:s}),this.handleKickOut())}}unlistenBroadcastChannel(){new BroadcastChannel(M).close()}notifyOtherTabsLogin(){new BroadcastChannel(M).postMessage({type:o.KICK_OUT,appId:this.store.appId,tabId:this.store.tabId})}async connectWebSocket(e){if(!e)throw Error("connect websocket error, not found login user token");this.imClient=new U({token:e,wsUrl:`${this.config.websocketHost}/ws`},this.logger),this.imClient.on(O.OPEN,()=>{this.store.set(N.IS_CONNECTED,!0)}),this.imClient.on(O.KICK_OFF,()=>{this.store.set(N.IS_CONNECTED,!1)}),this.imClient.on(O.CLOSE,()=>{this.store.set(N.IS_CONNECTED,!1)}),this.imClient.on(O.MESSAGE,e=>{this.handlePushMessage(e)}),this.imClient.connect()}disconnectWebSocket(){this.imClient&&(this.imClient.disconnect(),this.imClient=null)}assertReady(){if(!this.store.ready)throw{code:g.SDK_ERROR,msg:"sdk not ready"}}handleException(e){return this.logger.error("[ChatSDK Error]",e),{ok:!1,code:e.code||g.SDK_ERROR,msg:e.msg||e.message||"sdk error"}}}const G=new Map;function L(e){return{setLogLevel(t){e.setLogLevel(t)},login:t=>e.login(t),logout:()=>e.logout(),initialChat:t=>e.initialChat(t),addGroupMember:(t,s)=>e.addGroupMember(t,s),getCurrentFeed:()=>e.getCurrentFeed(),getMessageList:t=>e.getMessageList(t),uploadFile:t=>e.uploadFile(t),sendMessage:t=>e.sendMessage(t),sendMessageReadReceipt:t=>e.sendMessageReadReceipt(t),markAllMessagesAsRead:t=>e.markAllMessagesAsRead(t),recallMessage:t=>e.recallMessage(t),get currentUserId(){return e.currentUserId},get currentChatId(){return e.currentChatId},get isReady(){return e.isReady},on:(t,s)=>e.on(t,s),once:(t,s)=>e.once(t,s),off:(t,s)=>e.off(t,s)}}var v={create:function(e,t,s){if(G.has(e))return L(G.get(e));const r=new F(e,t,s);return G.set(e,r),L(r)}};export{g as ChatSdkErrorCode,E as ChatSdkEvent,a as ChatType,h as MessageKind,d as MessageOperation,c as MessageType,l as RequestDirection,v as default};
|
package/dist/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,"__esModule",{value:!0});var e,t,s,r,i,n,o,a,h,d,c=require("crypto-js"),g=require("axios"),E=require("@fingerprintjs/fingerprintjs"),l=require("js-cookie");function u(e,t,s){return{ok:!1,code:e||exports.ChatSdkErrorCode.SDK_ERROR,msg:t||"sdk error",msg_i18n:s}}function _(e){return{ok:!0,data:e}}!function(e){e[e.KICK_OFF=4001]="KICK_OFF"}(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.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.KICK_OUT=0]="KICK_OUT"}(s||(s={})),exports.ChatType=void 0,(r=exports.ChatType||(exports.ChatType={}))[r.singleChat=1]="singleChat",r[r.groupChat=2]="groupChat",exports.MessageKind=void 0,(i=exports.MessageKind||(exports.MessageKind={}))[i.normal=0]="normal",i[i.system=1]="system",exports.MessageType=void 0,(n=exports.MessageType||(exports.MessageType={}))[n.text=0]="text",n[n.image=1]="image",n[n.audio=3]="audio",n[n.video=4]="video",n[n.file=5]="file",n[n.mergeForward=6]="mergeForward",n[n.sticker=7]="sticker",n[n.richText=8]="richText",n[n.contact=9]="contact",n[n.communication=10]="communication",n[n.mixedImageText=11]="mixedImageText",n[n.luckyGift=14]="luckyGift",n[n.fileGroup=15]="fileGroup",n[n.cardMsg=16]="cardMsg",exports.MessageOperation=void 0,(o=exports.MessageOperation||(exports.MessageOperation={}))[o.normal=0]="normal",o[o.recall=1]="recall",exports.ChatSdkErrorCode=void 0,(a=exports.ChatSdkErrorCode||(exports.ChatSdkErrorCode={}))[a.NETWORK_ERROR=-1e4]="NETWORK_ERROR",a[a.SDK_ERROR=-10001]="SDK_ERROR",exports.ChatSdkEvent=void 0,(h=exports.ChatSdkEvent||(exports.ChatSdkEvent={})).SDK_READY="SDK_READY",h.SDK_NOT_READY="SDK_NOT_READY",h.SDK_KICKOUT="SDK_KICKOUT",h.FEED_UPDATED="FEED_UPDATED",h.MESSAGE_RECEIVED="MESSAGE_RECEIVED",h.MESSAGE_UPDATED="MESSAGE_UPDATED",h.MESSAGE_RECEIPT_RECEIVED="MESSAGE_RECEIPT_RECEIVED",exports.RequestDirection=void 0,(d=exports.RequestDirection||(exports.RequestDirection={}))[d.up=0]="up",d[d.down=1]="down";const p="[TYPEX_AGENT_JS_SDK]";class S{level=0;setLogLevel(e){this.level=e}getLogLevel(){return this.level}shouldPrint(e){return e>=this.level}debug(...e){this.shouldPrint(0)&&console.debug(`${p}[DEBUG]`,...e)}info(...e){this.shouldPrint(0)&&console.info(`${p}[INFO]`,...e)}warn(...e){this.shouldPrint(1)&&console.warn(`${p}[WARN]`,...e)}error(...e){this.shouldPrint(2)&&console.error(`${p}[ERROR]`,...e)}}function C(e){return(new TextEncoder).encode(e).buffer}async function T(e,t){return window.crypto&&window.crypto.subtle?await async function(e,t){const s=C(t),r=C(e),i=await crypto.subtle.importKey("raw",s,{name:"HMAC",hash:{name:"SHA-256"}},!1,["sign"]),n=await crypto.subtle.sign("HMAC",i,r);return Array.from(new Uint8Array(n)).map(e=>e.toString(16).padStart(2,"0")).join("")}(e,t):function(e,t){const s=c.HmacSHA256(e,t);return c.enc.Hex.stringify(s)}(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 r of t)s+=m(e[r]);return s}};class R{instance;developer;logger;store;constructor(e,t){this.logger=t.logger,this.store=t.store,this.developer=e.developer;const s=e.baseURL.replace(/\/$/,"");this.instance=g.create({baseURL:s,headers:{...e.defaultHeaders??{}},timeout:e.timeout??3e4}),this.setupInterceptors()}setupInterceptors(){this.instance.interceptors.request.use(e=>(e.headers=e.headers||{},e.headers["Content-Type"]||(e.headers["Content-Type"]="application/json"),e.headers.Platform="web",e.headers.AppID=this.store.appId,e.url?.startsWith("/open")&&(e.headers.Authorization=`Bearer ${this.store.token}`),this.developer&&!e.ignoreDeveloper&&(e.headers["x-developer"]=this.developer),e))}async get(e,t={},s={}){return this.request({url:e,method:"GET",params:t,...s})}async post(e,t,s={}){return this.request({url:e,method:"POST",data:t,...s})}async request(e){try{const{needSign:t,...s}=e;if(t&&"POST"===s.method?.toUpperCase()&&s.data){const t=this.store.currentUser;if(!t){const e="[HttpClient] HttpClient needs make sign but not found login user";return this.logger.error(e),u(exports.ChatSdkErrorCode.SDK_ERROR,e)}try{const r=await(async(e,t)=>{const s=m(e);return await T(s,t)})(s.data,t.secretKey);e.headers||(e.headers={}),e.headers.sign=r}catch(e){const t=`[HttpClient] HttpClient make sign error: ${e.message}`;return this.logger.error(t),u(exports.ChatSdkErrorCode.SDK_ERROR,t)}}const r=await this.instance.request({...s,headers:{...e.headers||{}}}),i=r.data;return 0!==i.code?(this.logger.error("[HttpClient]","Business server response error:",r),{ok:!1,code:i.code,msg:i.msg,msg_i18n:i.msg_i18n}):{ok:!0,data:i.data}}catch(e){return this.handleError(e)}}handleError(e){return"ECONNABORTED"===e.code?{ok:!1,code:exports.ChatSdkErrorCode.NETWORK_ERROR,msg:e.message||"request timeout"}:{ok:!1,code:exports.ChatSdkErrorCode.NETWORK_ERROR,msg:e.message||"network error"}}}class I{listeners=new Map;logger;constructor(e){this.logger=e}on(e,t){this.listeners.has(e)||this.listeners.set(e,new Set),this.listeners.get(e).add(t)}once(e,t){const s=r=>{t(r),this.off(e,s)};this.on(e,s)}off(e,t){this.listeners.has(e)&&(t?this.listeners.get(e).delete(t):this.listeners.delete(e))}emit(e,t){if(this.listeners.has(e))for(const s of this.listeners.get(e))try{s(t)}catch(t){this.logger.error(`[EventCore] handler error on "${String(e)}":`,t)}}clear(){this.listeners.clear()}}var D,A,O,N;!function(e){e.INIT="INIT",e.CONNECTING="CONNECTING",e.CONNECTED="CONNECTED",e.DISCONNECTED="DISCONNECTED",e.CLOSED="CLOSED"}(D||(D={})),function(e){e.OPEN="OPEN",e.ERROR="ERROR",e.CLOSE="CLOSE",e.MESSAGE="MESSAGE",e.STATUS_CHANGE="STATUS_CHANGE"}(A||(A={}));class b extends I{ws;options;status=D.INIT;constructor(e,t){super(t),this.options=e}connect(){if(this.status===D.CONNECTING||this.status===D.CONNECTED)return void this.logger.debug("[CONNECTION]","WebSocket is connecting or connected,current connect status is",`[${this.status}]`);this.logger.debug("[CONNECTION][connect]","WebSocket is connecting"),this.setStatus(D.CONNECTING);const e=new WebSocket(`${this.options.url}?token=${this.options.token}&platform=web`);this.ws=e,e.onopen=()=>{this.logger.debug("[CONNECTION][ws.onopen]","WebSocket is connected"),this.setStatus(D.CONNECTED),this.emit(A.OPEN)},e.onmessage=e=>{this.logger.debug("[CONNECTION][ws.onmessage]","WebSocket received a message",e.data),this.emit(A.MESSAGE,e.data)},e.onerror=e=>{this.logger.error("[CONNECTION][ws.onerror]","WebSocket connect error",e),this.emit(A.ERROR,e)},e.onclose=e=>{this.logger.debug("[CONNECTION][ws.onclose]","WebSocket connect be closed",e),this.setStatus(D.DISCONNECTED),this.emit(A.CLOSE,e)}}close(){this.ws?.close(),this.ws=void 0,this.setStatus(D.CLOSED)}send(e){if(this.status!==D.CONNECTED)throw new Error("WebSocket is not connected");this.ws.send(e)}getStatus(){return this.status}setStatus(e){this.status!==e&&(this.status=e,this.emit(A.STATUS_CHANGE,e))}}class f{connection;pingTimeout;pongTimeout;pingTimer;pongTimer;logger;constructor(e,t,s={}){this.connection=e,this.pingTimeout=s.pingTimeout??3e4,this.pongTimeout=s.pongTimeout??2e4,this.logger=t}ping(e){this.logger.debug("[Heartbeat]","Heartbeat ping"),this.stop(),this.pingTimer=window.setTimeout(()=>{try{this.connection.send(JSON.stringify({type:0})),this.logger.debug("[Heartbeat]","Heartbeat send PING"),this.pong(e)}catch{}},this.pingTimeout)}pong(e){clearTimeout(this.pongTimer),this.pongTimer=window.setTimeout(()=>{e?.(),this.logger.debug("[Heartbeat]","Heartbeat called PONG callback")},this.pongTimeout)}stop(){this.logger.debug("[Heartbeat]","Heartbeat stop"),clearTimeout(this.pingTimer),clearTimeout(this.pongTimer),this.pingTimer=void 0,this.pongTimer=void 0}}class P{connection;baseInterval=1e3;maxAttempts=1/0;attempts=0;timer;enabled=!1;logger;constructor(e,t,s={}){this.logger=t,this.connection=e,s.baseInterval&&(this.baseInterval=s.baseInterval),s.maxAttempts&&(this.maxAttempts=s.maxAttempts),this.bindEvents()}bindEvents(){this.connection.on(A.CLOSE,()=>{this.enabled&&this.scheduleReconnect()}),this.connection.on(A.OPEN,()=>{this.reset()})}start(){this.logger.debug("[Reconnector]","Reconnector start"),this.enabled=!0}stop(){this.logger.debug("[Reconnector]","Reconnector stop"),this.enabled=!1,this.clearTimer()}scheduleReconnect(){if(this.logger.debug("[Reconnector]",`Reconnector scheduleReconnect, attempts: ${this.attempts}, maxAttempts: ${this.maxAttempts}`),this.attempts>=this.maxAttempts)return;this.attempts++;const e=this.baseInterval*Math.min(this.attempts,10);this.clearTimer(),this.timer=window.setTimeout(()=>{this.connection.connect()},e)}reset(){this.logger.debug("[Reconnector]","Reconnector reset"),this.attempts=0,this.clearTimer()}clearTimer(){this.timer&&(clearTimeout(this.timer),this.timer=void 0)}}!function(e){e.OPEN="OPEN",e.ERROR="ERROR",e.CLOSE="CLOSE",e.MESSAGE="MESSAGE",e.STATUS_CHANGE="STATUS_CHANGE",e.KICK_OFF="KICK_OFF"}(O||(O={}));class U extends I{connection;reconnector;heartbeat;constructor(e,t){super(t),this.connection=new b({url:e.wsUrl,token:e.token},t),this.reconnector=new P(this.connection,t),this.heartbeat=new f(this.connection,t),this.bindEvents()}connect(){this.reconnector.start(),this.connection.connect()}disconnect(){this.reconnector.stop(),this.heartbeat.stop(),this.connection.close()}startPing(){this.heartbeat.ping(()=>{this.disconnect();const e=setTimeout(()=>{this.connect(),clearTimeout(e)},1e4)})}bindEvents(){this.connection.on(A.OPEN,()=>{this.emit(O.OPEN),this.startPing()}),this.connection.on(A.CLOSE,t=>{if(t.code===e.KICK_OFF)return this.logger.warn("[IMClient][CLOSE][KICK_OFF]","You has been kicked off"),this.emit(O.KICK_OFF),void this.disconnect();this.emit(O.CLOSE)}),this.connection.on(A.MESSAGE,e=>{this.handleRawMessage(e)}),this.connection.on(A.STATUS_CHANGE,e=>{this.emit(O.STATUS_CHANGE,e)}),this.connection.on(A.ERROR,e=>{this.emit(O.ERROR,e)})}handleRawMessage(e){try{const s=JSON.parse(e);if(s.type===t.PONG_MESSAGE?this.startPing():this.sendAck(s.id),s.type===t.BIG_PACKAGE_PUSH)for(const e of s.content.big_push)this.emit(O.MESSAGE,e);else this.emit(O.MESSAGE,s)}catch(e){this.logger.error("[IMClient][handleRawMessage]","Message raw data json.parse error",e),this.emit(O.ERROR,e)}}sendAck(e){this.connection.send(JSON.stringify({type:1,ids:[e]}))}}!function(e){e.APP_ID="appId",e.TOKEN="token",e.CURRENT_USER="currentUser",e.CURRENT_FEED="currentFeed",e.SDK_READY="sdkReady",e.IS_CONNECTED="isConnected",e.DEVICE_ID="typeximDeviceId",e.BROWSER_FINGERPRINT="typeximBrowserFingerprint",e.TAB_ID="typeximTabId"}(N||(N={}));class y extends I{state={};constructor(e){super(e)}set(e,t){this.logger.debug("[Store] set:",e,t),this.state[e]=t,this.emit("change",{key:e,value:t})}get(e){return this.logger.debug("[Store] get:",e,this.state[e]),this.state[e]}remove(e){this.logger.debug("[Store] remove:",e,this.state[e]),delete this.state[e],this.emit("change",{key:e,value:void 0})}clear(){this.logger.debug("[Store] clear",this.state),this.state={appId:this.state.appId,token:this.state.token,typeximBrowserFingerprint:this.state.typeximBrowserFingerprint},this.emit("clear",void 0)}setWithLocal(e,t){this.logger.debug("[Store] setWithLocal:",e,t),this.set(e,t),localStorage.setItem(e,JSON.stringify(t))}getWithLocal(e){if(this.logger.debug("[Store] getWithLocal:",e,this.state[e]),this.state[e])return this.state[e];const t=localStorage.getItem(e);return t?JSON.parse(t):void 0}removeWithLocal(e){this.logger.debug("[Store] removeWithLocal:",e,this.state[e]),localStorage.removeItem(e),this.remove(e)}setWithSession(e,t){this.logger.debug("[Store] setWithSession:",e,t),this.set(e,t),sessionStorage.setItem(e,JSON.stringify(t))}getWithSession(e){if(this.logger.debug("[Store] getWithSession:",e,this.state[e]),this.state[e])return this.state[e];const t=sessionStorage.getItem(e);return t?JSON.parse(t):void 0}removeWithSession(e){this.logger.debug("[Store] removeWithSession:",e,this.state[e]),sessionStorage.removeItem(e),this.remove(e)}onChange(e){this.on("change",e)}offChange(e){this.off("change",e)}onClear(e){this.on("clear",e)}get appId(){return this.logger.debug("[Store] get appId",this.state.appId),this.state.appId}get ready(){return this.logger.debug("[Store] get ready",this.state.sdkReady),!!this.state.sdkReady}get deviceId(){const e=this.getWithLocal(N.DEVICE_ID);return this.logger.debug("[Store] get deviceId",e),e}get currentUser(){return this.logger.debug("[Store] get currentUser",this.state.currentUser),this.state.currentUser}get currentChatId(){return this.logger.debug("[Store] get currentChatId",this.state.currentFeed?.chat_id),this.state.currentFeed?.chat_id}get currentFeed(){return this.logger.debug("[Store] get currentFeed",this.state.currentFeed),this.state.currentFeed}get sessionId(){return this.logger.debug("[Store] get sessionId",this.state.currentUser?.sessionId),this.state.currentUser?.sessionId}get token(){return this.logger.debug("[Store] get token",this.state.token),this.state.token}get browserFingerprint(){const e=this.getWithLocal(N.BROWSER_FINGERPRINT);return this.logger.debug("[Store] get browserFingerprint",e),e}get tabId(){const e=this.getWithSession(N.TAB_ID);return this.logger.debug("[Store] get tabId",e),e}}class M{version;constructor(){this.version=0}increment(){this.version++}get currentVersion(){return this.version}check(e){return e===this.version}}const k="@typexim/agent-js-sdk_broadcast_channel";class v{config;logger;http;imClient=null;store;events;version;loadFeedAbortController=null;constructor(e,t,s){this.logger=new S,this.store=new y(this.logger),this.events=new I(this.logger),this.store.set(N.APP_ID,e),this.store.set(N.TOKEN,t),this.config=s,this.version=new M,this.http=new R({baseURL:s.httpHost,developer:s.developer},{logger:this.logger,store:this.store}),this.generateTabId(),this.generateBrowserFingerprint(),this.listenBroadcastChannel()}setLogLevel(e){this.logger.setLogLevel(e)}async login(e){try{const t={...e||{}};if(t.userId&&!t.busiToken)return u(exports.ChatSdkErrorCode.SDK_ERROR,"Invalid param: userId and busiToken must be provided together");if(!t.userId){const e=this.store.browserFingerprint||await this.generateBrowserFingerprint();t.userId=e}const s=await this.innerRegister(t);if(!s.ok||!s.data)return this.logger.error("[InternalChatSdk] innerRegister failed",s),u(s.code,s.msg,s.msg_i18n);const r=s.data,i=await this.requestDeviceId(),n=await this.innerLogin(r,i,t);if(!n.ok||!n.data)return this.logger.error("[InternalChatSdk] innerLogin failed",n),u(n.code,n.msg,n.msg_i18n);const o=l.get("sessionid");if(!o)throw new Error("Login failed, not found sessionid");const a=n.data||{};return a.sessionId=o,a.secretKey=n.data.key,await Promise.all([this.syncLoginState(a),this.connectWebSocket(o)]),this.notifyOtherTabsLogin(),_({id:a.id,userId:t.userId,name:a.name,avatar:a.avatar,email:a.email})}catch(e){return this.handleException(e)}}innerRegister(e){return this.http.post("/open/user/register",{userID:e.userId,name:e.name,avatar:e.avatar,email:e.email,passWord:e.password,userBuf:e.userBuf,busiToken:e.busiToken})}innerLogin(e,t,s){return this.http.post("/open/user/login",{uid:e,busi_token:s.busiToken,device_id:t})}generateTabId(){const e=this.store.getWithSession(N.TAB_ID);if(e)return e;const t=`${this.store.appId}_${Date.now()}_${Math.random().toString(36).substring(2,15)}`;return this.store.setWithSession(N.TAB_ID,t),t}async generateBrowserFingerprint(){try{const e=this.store.getWithLocal(N.BROWSER_FINGERPRINT);if(e)return this.logger.debug("[ChatSdk] generateBrowserFingerprint success from localstorage",e),e;const t=await E.load(),s=await t.get();return this.logger.debug("[ChatSdk] generateBrowserFingerprint success",s.visitorId),this.store.setWithLocal(N.BROWSER_FINGERPRINT,s.visitorId),s.visitorId}catch(e){this.logger.info("[ChatSdk] FingerprintJS generateBrowserFingerprint Error",e);const t=`${Date.now()}_${Math.random().toString(36).substring(2,15)}`;return this.logger.debug("[ChatSdk] random generateBrowserFingerprint success",t),this.store.setWithLocal(N.BROWSER_FINGERPRINT,t),t}}async loadFeed(){const e=this.version.currentVersion;this.loadFeedAbortController&&this.loadFeedAbortController.abort(),this.loadFeedAbortController=new AbortController;const t=await this.http.get("/feed",{limit:10},{signal:this.loadFeedAbortController.signal}).catch(e=>{this.logger.error("[ChatSdk] loadFeed Error",e)});this.loadFeedAbortController=null;const s=this.version.check(e);if(!t||!s)return;const r=t.data?.feed_list?.find(e=>e.chat_type===exports.ChatType.groupChat);t.ok&&(this.logger.debug("[ChatSdk][FEED_UPDATED] loadFeed success",r),this.store.set(N.CURRENT_FEED,r),this.events.emit(exports.ChatSdkEvent.FEED_UPDATED,r))}async syncLoginState(e){this.store.set(N.CURRENT_USER,e),this.store.set(N.SDK_READY,!0),await this.loadFeed(),this.events.emit(exports.ChatSdkEvent.SDK_READY)}syncLogoutState(){this.unlistenBroadcastChannel(),this.store.set(N.CURRENT_USER,void 0),this.store.set(N.SDK_READY,!1),this.store.set(N.CURRENT_FEED,void 0),this.events.emit(exports.ChatSdkEvent.SDK_NOT_READY)}async requestDeviceId(){const e=this.store.getWithLocal(N.DEVICE_ID);if(e)return this.logger.debug("[ChatSdk] requestDeviceId success from localstorage",e),e;const t=await this.http.post("/device_api/device_id",{platform:"web",hash_str:this.store.browserFingerprint||""}).catch(e=>{this.logger.error("[ChatSdk] requestDeviceId Error",e)});if(t?.ok&&t?.data)return this.logger.debug("[ChatSdk] requestDeviceId success",t.data),this.store.setWithLocal(N.DEVICE_ID,t.data),t.data;if(this.store.browserFingerprint)return this.logger.debug("[ChatSdk] use browserFingerprint as deviceId",this.store.browserFingerprint),this.store.setWithLocal(N.DEVICE_ID,this.store.browserFingerprint),this.store.browserFingerprint;const s=`${Date.now()}_${Math.random().toString(36).substring(2,15)}`;return this.logger.debug("[ChatSdk] random generateDeviceId success",s),this.store.setWithLocal(N.DEVICE_ID,s),s}async logout(){try{if(!this.store.currentUser)return _(null);const e=await this.http.get("/user/logout");return e.ok?(this.syncLogoutState(),this.disconnectWebSocket(),_(null)):u(e.code,e.msg,e.msg_i18n)}catch(e){return this.handleException(e)}}async addGroupMember(e,t){try{if(this.assertReady(),!e)return u(exports.ChatSdkErrorCode.SDK_ERROR,"not found chat id");if(!t?.length)return _(null);const s=this.store.currentFeed;if(!s)return u(exports.ChatSdkErrorCode.SDK_ERROR,"not found current feed");const r=await this.getChatMembers(s.chat_id,s.chat_member);if(!r.ok)return u(r.code,r.msg,r.msg_i18n);const i=(r.data||[]).map(e=>e.user_id),n=t.filter(e=>!i.includes(e)),o=await this.addMember(n,s.chat_id);return o.ok?_(o.data):u(o.code,o.msg,o.msg_i18n)}catch(e){return this.handleException(e)}}async initialChat(e){try{this.assertReady();const t=this.store.currentFeed;if(!t){const t=await this.createFeed(e.receiverIds);return t.ok&&t.data?(this.store.set(N.CURRENT_FEED,t.data),_(t.data.chat_id)):u(t.code,t.msg,t.msg_i18n)}const s=await this.addGroupMember(t.chat_id,e.receiverIds);return s.ok?_(t.chat_id):s}catch(e){return this.handleException(e)}}async getCurrentFeed(){try{return this.assertReady(),{ok:!0,data:this.store.currentFeed}}catch(e){return this.handleException(e)}}async getMessageList(e){try{this.assertReady();const t=this.store.currentFeed;if(!t)return u(exports.ChatSdkErrorCode.SDK_ERROR,"No feed found");const{chat_id:s,first_position:r,last_message_position:i}=t,{positions:n,nextPosition:o,hasMore:a}=(e=>{const t=[];if(e.direction===exports.RequestDirection.up){let s=e.startPosition??e.maxPosition;for(;t.length<e.limit&&s>=e.minPosition;)t.push(s),s--;const r=s>=e.minPosition;let i;return r&&(i=s),{positions:t,nextPosition:i,hasMore:r}}{let s=e.startPosition??e.minPosition;for(;t.length<e.limit&&s<=e.maxPosition;)t.push(s),s++;const r=s<=e.maxPosition;let i;return r&&(i=s),{positions:t,nextPosition:i,hasMore:r}}})({maxPosition:i,minPosition:r,startPosition:e.messagePosition,limit:e.limit,direction:e.direction??exports.RequestDirection.up});if(n.length>0){const e=await this.http.post("/message/get_by_position",{chat_position:{[s]:n}});if(e.ok&&e.data?.[s]){return _({hasMore:a,list:e.data[s].reverse().filter(e=>e.message_kind_id!==exports.MessageKind.system&&e.operation!==exports.MessageOperation.recall),nextMessagePosition:o})}return u(e.code,e.msg,e.msg_i18n)}return _({hasMore:!1,list:[]})}catch(e){return this.handleException(e)}}async sendMessage(e){try{this.assertReady();const t=e.messageType;switch(t){case exports.MessageType.text:return this.sendTextMessage(e);case exports.MessageType.image:return this.sendImageMessage(e);case exports.MessageType.video:return this.sendVideoMessage(e);case exports.MessageType.file:return this.sendFileMessage(e);default:return this.logger.warn("Unsupported message type: ",t),u(exports.ChatSdkErrorCode.SDK_ERROR,`Unsupported message type: ${t}`)}}catch(e){return this.handleException(e)}}async sendTextMessage(e){return this.http.post("/message/send_text",{chat_id:e.chatId,client_msg_id:e.clientMsgId,text:e.text.trim()},{needSign:!0})}async sendImageMessage(e){return this.http.post("/message/send_image",{chat_id:e.chatId,client_msg_id:e.clientMsgId,object_url:e.objectUrl,width:e.width,height:e.height},{needSign:!0})}async sendVideoMessage(e){return this.http.post("/message/send_video",{chat_id:e.chatId,client_msg_id:e.clientMsgId,video_url:e.objectUrl,duration_second:e.duration,image_url:e.coverUrl,width:e.width,height:e.height},{needSign:!0})}async sendFileMessage(e){return this.http.post("/message/send_file",{chat_id:e.chatId,client_msg_id:e.clientMsgId,object_url:e.objectUrl,file_name:e.fileName,file_size:e.fileSize},{needSign:!0})}async uploadFile(e){const{chatId:t,fileContent:s,fileFormat:r,fileName:i,fileType:n,onUploadProgress:o}=e,a=new FormData;return a.append("file_content",s),a.append("file_type",n),a.append("file_name",i),a.append("file_format",r),a.append("chat_id",t),this.http.post("/chat/upload",a,{needSign:!1,ignoreDeveloper:!0,onUploadProgress:o,headers:{"Content-Type":"multipart/form-data"}})}async sendMessageReadReceipt(e){try{return this.assertReady(),e.messageIds?.length?this.http.post("/message/read",{chat_id:e.chatId,message_ids:e.messageIds},{needSign:!0}):_(null)}catch(e){return this.handleException(e)}}async markAllMessagesAsRead(e){const t=this.store.currentFeed?.unread_message_ids||[];return this.sendMessageReadReceipt({chatId:e,messageIds:t})}async recallMessage(e){try{return this.assertReady(),e.messageIds.length?this.http.post("/message/remove",{chat_id:e.chatId,message_ids:e.messageIds,two_way:1},{needSign:!0}):_(null)}catch(e){return this.handleException(e)}}async createFeed(e){return await this.http.post("/chat/group",{receiver_ids:e,group_type:0,name:`User ${this.store.currentUser?.name||this.store.currentUser?.id}`},{needSign:!0})}async getChatMembers(e,t){return this.http.post("/chat/chatter_info",JSON.stringify({chatters:{[e]:t}}))}async addMember(e,t){return t?e.length?this.http.post("/chat/group/add_member",{user_ids:e,chat_id:t},{needSign:!0}):_(null):u(exports.ChatSdkErrorCode.SDK_ERROR,"not found chat id")}handlePushMessage(e){switch(this.logger.debug("handlePushMessage",e),e.type){case t.CREATE_FEED:case t.UPDATE_FEED:this.handleFeedUpdate(e);break;case t.ADD_MESSAGE:this.handleAddMessage(e);break;case t.UPDATE_MESSAGE:this.handleUpdateMessage(e);break;case t.READ_MESSAGE:this.handleReadMessage(e);break;case t.KICK_OUT_DEVICE:this.handleKickOut()}}handleFeedUpdate(e){this.store.set(N.CURRENT_FEED,e.content),this.events.emit(exports.ChatSdkEvent.FEED_UPDATED,e.content)}async handleAddMessage(e){e.content.chat_id===this.store.currentChatId&&(await this.loadFeed(),this.events.emit(exports.ChatSdkEvent.MESSAGE_RECEIVED,e.content))}async handleUpdateMessage(e){e.content.chat_id===this.store.currentChatId&&(await this.loadFeed(),this.events.emit(exports.ChatSdkEvent.MESSAGE_UPDATED,e.content))}async handleReadMessage(e){e.content.chat_id===this.store.currentChatId&&(await this.loadFeed(),this.events.emit(exports.ChatSdkEvent.MESSAGE_RECEIPT_RECEIVED,{chatId:e.content.chat_id,messageIds:e.content.message_ids,readerUserIds:e.content.reader_ids}))}handleKickOut(){this.syncLogoutState(),this.disconnectWebSocket(),this.events.emit(exports.ChatSdkEvent.SDK_KICKOUT)}on(e,t){return this.events.on(e,t)}once(e,t){return this.events.once(e,t)}off(e,t){return this.events.off(e,t)}get currentUserId(){return this.logger.debug("[InternalChatSdk] get currentUserId==>",this.store.currentUser),this.store.currentUser?.id}get currentChatId(){return this.logger.debug("[InternalChatSdk] get currentChatId==>",this.store.currentChatId),this.store.currentChatId}get isReady(){return this.logger.debug("[InternalChatSdk] get isReady==>",this.store.ready),this.store.ready}listenBroadcastChannel(){new BroadcastChannel(k).onmessage=e=>{const t=this.store.appId,r=this.store.tabId;e.data.type===s.KICK_OUT&&e.data.appId===t&&e.data.tabId!==r&&(this.logger.debug("[BroadcastChannel] message: kick out",{appId:t,sourceTabId:e.data.tabId,currentTabId:r}),this.handleKickOut())}}unlistenBroadcastChannel(){new BroadcastChannel(k).close()}notifyOtherTabsLogin(){new BroadcastChannel(k).postMessage({type:s.KICK_OUT,appId:this.store.appId,tabId:this.store.tabId})}async connectWebSocket(e){if(!e)throw Error("connect websocket error, not found login user token");this.imClient=new U({token:e,wsUrl:`${this.config.websocketHost}/ws`},this.logger),this.imClient.on(O.OPEN,()=>{this.store.set(N.IS_CONNECTED,!0)}),this.imClient.on(O.KICK_OFF,()=>{this.store.set(N.IS_CONNECTED,!1)}),this.imClient.on(O.CLOSE,()=>{this.store.set(N.IS_CONNECTED,!1)}),this.imClient.on(O.MESSAGE,e=>{this.handlePushMessage(e)}),this.imClient.connect()}disconnectWebSocket(){this.imClient&&(this.imClient.disconnect(),this.imClient=null)}assertReady(){if(!this.store.ready)throw{code:exports.ChatSdkErrorCode.SDK_ERROR,msg:"sdk not ready"}}handleException(e){return this.logger.error("[ChatSDK Error]",e),{ok:!1,code:e.code||exports.ChatSdkErrorCode.SDK_ERROR,msg:e.msg||e.message||"sdk error"}}}const w=new Map;function F(e){return{setLogLevel(t){e.setLogLevel(t)},login:t=>e.login(t),logout:()=>e.logout(),initialChat:t=>e.initialChat(t),addGroupMember:(t,s)=>e.addGroupMember(t,s),getCurrentFeed:()=>e.getCurrentFeed(),getMessageList:t=>e.getMessageList(t),uploadFile:t=>e.uploadFile(t),sendMessage:t=>e.sendMessage(t),sendMessageReadReceipt:t=>e.sendMessageReadReceipt(t),markAllMessagesAsRead:t=>e.markAllMessagesAsRead(t),recallMessage:t=>e.recallMessage(t),get currentUserId(){return e.currentUserId},get currentChatId(){return e.currentChatId},get isReady(){return e.isReady},on:(t,s)=>e.on(t,s),once:(t,s)=>e.once(t,s),off:(t,s)=>e.off(t,s)}}var L={create:function(e,t,s){if(w.has(e))return F(w.get(e));const r=new v(e,t,s);return w.set(e,r),F(r)}};exports.default=L;
|
|
1
|
+
"use strict";Object.defineProperty(exports,"__esModule",{value:!0});var e,t,s,r,i,n,o,a,h,d,c=require("crypto-js"),g=require("axios"),E=require("@fingerprintjs/fingerprintjs"),l=require("js-cookie");function u(e,t,s){return{ok:!1,code:e||exports.ChatSdkErrorCode.SDK_ERROR,msg:t||"sdk error",msg_i18n:s}}function _(e){return{ok:!0,data:e}}!function(e){e[e.KICK_OFF=4001]="KICK_OFF"}(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.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.KICK_OUT=0]="KICK_OUT"}(s||(s={})),exports.ChatType=void 0,(r=exports.ChatType||(exports.ChatType={}))[r.singleChat=1]="singleChat",r[r.groupChat=2]="groupChat",exports.MessageKind=void 0,(i=exports.MessageKind||(exports.MessageKind={}))[i.normal=0]="normal",i[i.system=1]="system",exports.MessageType=void 0,(n=exports.MessageType||(exports.MessageType={}))[n.text=0]="text",n[n.image=1]="image",n[n.audio=3]="audio",n[n.video=4]="video",n[n.file=5]="file",n[n.mergeForward=6]="mergeForward",n[n.sticker=7]="sticker",n[n.richText=8]="richText",n[n.contact=9]="contact",n[n.communication=10]="communication",n[n.mixedImageText=11]="mixedImageText",n[n.luckyGift=14]="luckyGift",n[n.fileGroup=15]="fileGroup",n[n.cardMsg=16]="cardMsg",exports.MessageOperation=void 0,(o=exports.MessageOperation||(exports.MessageOperation={}))[o.normal=0]="normal",o[o.recall=1]="recall",exports.ChatSdkErrorCode=void 0,(a=exports.ChatSdkErrorCode||(exports.ChatSdkErrorCode={}))[a.NETWORK_ERROR=-1e4]="NETWORK_ERROR",a[a.SDK_ERROR=-10001]="SDK_ERROR",exports.ChatSdkEvent=void 0,(h=exports.ChatSdkEvent||(exports.ChatSdkEvent={})).SDK_READY="SDK_READY",h.SDK_NOT_READY="SDK_NOT_READY",h.SDK_KICKOUT="SDK_KICKOUT",h.FEED_UPDATED="FEED_UPDATED",h.MESSAGE_RECEIVED="MESSAGE_RECEIVED",h.MESSAGE_UPDATED="MESSAGE_UPDATED",h.MESSAGE_RECEIPT_RECEIVED="MESSAGE_RECEIPT_RECEIVED",exports.RequestDirection=void 0,(d=exports.RequestDirection||(exports.RequestDirection={}))[d.up=0]="up",d[d.down=1]="down";const p="[TYPEX_AGENT_JS_SDK]";class S{level=0;setLogLevel(e){this.level=e}getLogLevel(){return this.level}shouldPrint(e){return e>=this.level}debug(...e){this.shouldPrint(0)&&console.debug(`${p}[DEBUG]`,...e)}info(...e){this.shouldPrint(0)&&console.info(`${p}[INFO]`,...e)}warn(...e){this.shouldPrint(1)&&console.warn(`${p}[WARN]`,...e)}error(...e){this.shouldPrint(2)&&console.error(`${p}[ERROR]`,...e)}}function C(e){return(new TextEncoder).encode(e).buffer}async function T(e,t){return window.crypto&&window.crypto.subtle?await async function(e,t){const s=C(t),r=C(e),i=await crypto.subtle.importKey("raw",s,{name:"HMAC",hash:{name:"SHA-256"}},!1,["sign"]),n=await crypto.subtle.sign("HMAC",i,r);return Array.from(new Uint8Array(n)).map(e=>e.toString(16).padStart(2,"0")).join("")}(e,t):function(e,t){const s=c.HmacSHA256(e,t);return c.enc.Hex.stringify(s)}(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 r of t)s+=m(e[r]);return s}};class R{instance;developer;logger;store;constructor(e,t){this.logger=t.logger,this.store=t.store,this.developer=e.developer;const s=e.baseURL.replace(/\/$/,"");this.instance=g.create({baseURL:s,headers:{...e.defaultHeaders??{}},timeout:e.timeout??3e4}),this.setupInterceptors()}setupInterceptors(){this.instance.interceptors.request.use(e=>(e.headers=e.headers||{},e.headers["Content-Type"]||(e.headers["Content-Type"]="application/json"),e.headers.Platform="web",e.headers.AppID=this.store.appId,e.url?.startsWith("/open")&&(e.headers.Authorization=`Bearer ${this.store.token}`),this.developer&&!e.ignoreDeveloper&&(e.headers["x-developer"]=this.developer),e))}async get(e,t={},s={}){return this.request({url:e,method:"GET",params:t,...s})}async post(e,t,s={}){return this.request({url:e,method:"POST",data:t,...s})}async request(e){try{const{needSign:t,...s}=e;if(t&&"POST"===s.method?.toUpperCase()&&s.data){const t=this.store.currentUser;if(!t){const e="[HttpClient] HttpClient needs make sign but not found login user";return this.logger.error(e),u(exports.ChatSdkErrorCode.SDK_ERROR,e)}try{const r=await(async(e,t)=>{const s=m(e);return await T(s,t)})(s.data,t.secretKey);e.headers||(e.headers={}),e.headers.sign=r}catch(e){const t=`[HttpClient] HttpClient make sign error: ${e.message}`;return this.logger.error(t),u(exports.ChatSdkErrorCode.SDK_ERROR,t)}}const r=await this.instance.request({...s,headers:{...e.headers||{}}}),i=r.data;return 0!==i.code?(this.logger.error("[HttpClient]","Business server response error:",r),{ok:!1,code:i.code,msg:i.msg,msg_i18n:i.msg_i18n}):{ok:!0,data:i.data}}catch(e){return this.handleError(e)}}handleError(e){return"ECONNABORTED"===e.code?{ok:!1,code:exports.ChatSdkErrorCode.NETWORK_ERROR,msg:e.message||"request timeout"}:{ok:!1,code:exports.ChatSdkErrorCode.NETWORK_ERROR,msg:e.message||"network error"}}}class I{listeners=new Map;logger;constructor(e){this.logger=e}on(e,t){this.listeners.has(e)||this.listeners.set(e,new Set),this.listeners.get(e).add(t)}once(e,t){const s=r=>{t(r),this.off(e,s)};this.on(e,s)}off(e,t){this.listeners.has(e)&&(t?this.listeners.get(e).delete(t):this.listeners.delete(e))}emit(e,t){if(this.listeners.has(e))for(const s of this.listeners.get(e))try{s(t)}catch(t){this.logger.error(`[EventCore] handler error on "${String(e)}":`,t)}}clear(){this.listeners.clear()}}var D,A,O,N;!function(e){e.INIT="INIT",e.CONNECTING="CONNECTING",e.CONNECTED="CONNECTED",e.DISCONNECTED="DISCONNECTED",e.CLOSED="CLOSED"}(D||(D={})),function(e){e.OPEN="OPEN",e.ERROR="ERROR",e.CLOSE="CLOSE",e.MESSAGE="MESSAGE",e.STATUS_CHANGE="STATUS_CHANGE"}(A||(A={}));class b extends I{ws;options;status=D.INIT;constructor(e,t){super(t),this.options=e}connect(){if(this.status===D.CONNECTING||this.status===D.CONNECTED)return void this.logger.debug("[CONNECTION]","WebSocket is connecting or connected,current connect status is",`[${this.status}]`);this.logger.debug("[CONNECTION][connect]","WebSocket is connecting"),this.setStatus(D.CONNECTING);const e=new WebSocket(`${this.options.url}?token=${this.options.token}&platform=web`);this.ws=e,e.onopen=()=>{this.logger.debug("[CONNECTION][ws.onopen]","WebSocket is connected"),this.setStatus(D.CONNECTED),this.emit(A.OPEN)},e.onmessage=e=>{this.logger.debug("[CONNECTION][ws.onmessage]","WebSocket received a message",e.data),this.emit(A.MESSAGE,e.data)},e.onerror=e=>{this.logger.error("[CONNECTION][ws.onerror]","WebSocket connect error",e),this.emit(A.ERROR,e)},e.onclose=e=>{this.logger.debug("[CONNECTION][ws.onclose]","WebSocket connect be closed",e),this.setStatus(D.DISCONNECTED),this.emit(A.CLOSE,e)}}close(){this.ws?.close(),this.ws=void 0,this.setStatus(D.CLOSED)}send(e){if(this.status!==D.CONNECTED)throw new Error("WebSocket is not connected");this.ws.send(e)}getStatus(){return this.status}setStatus(e){this.status!==e&&(this.status=e,this.emit(A.STATUS_CHANGE,e))}}class P{connection;pingTimeout;pongTimeout;pingTimer;pongTimer;logger;constructor(e,t,s={}){this.connection=e,this.pingTimeout=s.pingTimeout??3e4,this.pongTimeout=s.pongTimeout??2e4,this.logger=t}ping(e){this.logger.debug("[Heartbeat]","Heartbeat ping"),this.stop(),this.pingTimer=window.setTimeout(()=>{try{this.connection.send(JSON.stringify({type:0})),this.logger.debug("[Heartbeat]","Heartbeat send PING"),this.pong(e)}catch{}},this.pingTimeout)}pong(e){clearTimeout(this.pongTimer),this.pongTimer=window.setTimeout(()=>{e?.(),this.logger.debug("[Heartbeat]","PING timeout, called PING/PONG callback")},this.pongTimeout)}stop(){this.logger.debug("[Heartbeat]","Heartbeat stop"),clearTimeout(this.pingTimer),clearTimeout(this.pongTimer),this.pingTimer=void 0,this.pongTimer=void 0}}class f{connection;baseInterval=1e3;maxAttempts=1/0;attempts=0;timer;enabled=!1;logger;constructor(e,t,s={}){this.logger=t,this.connection=e,s.baseInterval&&(this.baseInterval=s.baseInterval),s.maxAttempts&&(this.maxAttempts=s.maxAttempts),this.bindEvents()}bindEvents(){this.connection.on(A.CLOSE,()=>{this.enabled&&this.scheduleReconnect()}),this.connection.on(A.OPEN,()=>{this.reset()})}start(){this.logger.debug("[Reconnector]","Reconnector start"),this.enabled=!0}stop(){this.logger.debug("[Reconnector]","Reconnector stop"),this.enabled=!1,this.clearTimer()}scheduleReconnect(){if(this.logger.debug("[Reconnector]",`Reconnector scheduleReconnect, attempts: ${this.attempts}, maxAttempts: ${this.maxAttempts}`),this.attempts>=this.maxAttempts)return;this.attempts++;const e=this.baseInterval*Math.min(this.attempts,10);this.clearTimer(),this.timer=window.setTimeout(()=>{this.connection.connect()},e)}reset(){this.logger.debug("[Reconnector]","Reconnector reset"),this.attempts=0,this.clearTimer()}clearTimer(){this.timer&&(clearTimeout(this.timer),this.timer=void 0)}}!function(e){e.OPEN="OPEN",e.ERROR="ERROR",e.CLOSE="CLOSE",e.MESSAGE="MESSAGE",e.STATUS_CHANGE="STATUS_CHANGE",e.KICK_OFF="KICK_OFF"}(O||(O={}));class U extends I{connection;reconnector;heartbeat;pongTimeoutCount=0;constructor(e,t){super(t),this.connection=new b({url:e.wsUrl,token:e.token},t),this.reconnector=new f(this.connection,t),this.heartbeat=new P(this.connection,t),this.bindEvents()}connect(){this.reconnector.start(),this.connection.connect()}disconnect(){this.reconnector.stop(),this.heartbeat.stop(),this.connection.close()}startPing(){this.heartbeat.ping(()=>{if(this.logger.warn("[IMClient][Heartbeat]","PONG timeout, current pong timeout count: ",this.pongTimeoutCount),this.pongTimeoutCount++,this.pongTimeoutCount>=5){this.disconnect();const e=setTimeout(()=>{this.connect(),clearTimeout(e)},1e4);return}this.startPing()})}bindEvents(){this.connection.on(A.OPEN,()=>{this.emit(O.OPEN),this.startPing()}),this.connection.on(A.CLOSE,t=>{if(t.code===e.KICK_OFF)return this.logger.warn("[IMClient][CLOSE][KICK_OFF]","You has been kicked off"),this.emit(O.KICK_OFF),void this.disconnect();this.emit(O.CLOSE)}),this.connection.on(A.MESSAGE,e=>{this.handleRawMessage(e)}),this.connection.on(A.STATUS_CHANGE,e=>{this.emit(O.STATUS_CHANGE,e)}),this.connection.on(A.ERROR,e=>{this.emit(O.ERROR,e)})}handleRawMessage(e){try{const s=JSON.parse(e);if(s.type===t.PONG_MESSAGE?this.startPing():this.sendAck(s.id),s.type===t.BIG_PACKAGE_PUSH)for(const e of s.content.big_push)this.emit(O.MESSAGE,e);else this.emit(O.MESSAGE,s)}catch(e){this.logger.error("[IMClient][handleRawMessage]","Message raw data json.parse error",e),this.emit(O.ERROR,e)}}sendAck(e){this.connection.send(JSON.stringify({type:1,ids:[e]}))}}!function(e){e.APP_ID="appId",e.TOKEN="token",e.CURRENT_USER="currentUser",e.CURRENT_FEED="currentFeed",e.SDK_READY="sdkReady",e.IS_CONNECTED="isConnected",e.DEVICE_ID="typeximDeviceId",e.BROWSER_FINGERPRINT="typeximBrowserFingerprint",e.TAB_ID="typeximTabId"}(N||(N={}));class y extends I{state={};constructor(e){super(e)}set(e,t){this.logger.debug("[Store] set:",e,t),this.state[e]=t,this.emit("change",{key:e,value:t})}get(e){return this.logger.debug("[Store] get:",e,this.state[e]),this.state[e]}remove(e){this.logger.debug("[Store] remove:",e,this.state[e]),delete this.state[e],this.emit("change",{key:e,value:void 0})}clear(){this.logger.debug("[Store] clear",this.state),this.state={appId:this.state.appId,token:this.state.token,typeximBrowserFingerprint:this.state.typeximBrowserFingerprint},this.emit("clear",void 0)}setWithLocal(e,t){this.logger.debug("[Store] setWithLocal:",e,t),this.set(e,t),localStorage.setItem(e,JSON.stringify(t))}getWithLocal(e){if(this.logger.debug("[Store] getWithLocal:",e,this.state[e]),this.state[e])return this.state[e];const t=localStorage.getItem(e);return t?JSON.parse(t):void 0}removeWithLocal(e){this.logger.debug("[Store] removeWithLocal:",e,this.state[e]),localStorage.removeItem(e),this.remove(e)}setWithSession(e,t){this.logger.debug("[Store] setWithSession:",e,t),this.set(e,t),sessionStorage.setItem(e,JSON.stringify(t))}getWithSession(e){if(this.logger.debug("[Store] getWithSession:",e,this.state[e]),this.state[e])return this.state[e];const t=sessionStorage.getItem(e);return t?JSON.parse(t):void 0}removeWithSession(e){this.logger.debug("[Store] removeWithSession:",e,this.state[e]),sessionStorage.removeItem(e),this.remove(e)}onChange(e){this.on("change",e)}offChange(e){this.off("change",e)}onClear(e){this.on("clear",e)}get appId(){return this.logger.debug("[Store] get appId",this.state.appId),this.state.appId}get ready(){return this.logger.debug("[Store] get ready",this.state.sdkReady),!!this.state.sdkReady}get deviceId(){const e=this.getWithLocal(N.DEVICE_ID);return this.logger.debug("[Store] get deviceId",e),e}get currentUser(){return this.logger.debug("[Store] get currentUser",this.state.currentUser),this.state.currentUser}get currentChatId(){return this.logger.debug("[Store] get currentChatId",this.state.currentFeed?.chat_id),this.state.currentFeed?.chat_id}get currentFeed(){return this.logger.debug("[Store] get currentFeed",this.state.currentFeed),this.state.currentFeed}get sessionId(){return this.logger.debug("[Store] get sessionId",this.state.currentUser?.sessionId),this.state.currentUser?.sessionId}get token(){return this.logger.debug("[Store] get token",this.state.token),this.state.token}get browserFingerprint(){const e=this.getWithLocal(N.BROWSER_FINGERPRINT);return this.logger.debug("[Store] get browserFingerprint",e),e}get tabId(){const e=this.getWithSession(N.TAB_ID);return this.logger.debug("[Store] get tabId",e),e}}class M{version;constructor(){this.version=0}increment(){this.version++}get currentVersion(){return this.version}check(e){return e===this.version}}const k="@typexim/agent-js-sdk_broadcast_channel";class v{config;logger;http;imClient=null;store;events;version;loadFeedAbortController=null;constructor(e,t,s){this.logger=new S,this.store=new y(this.logger),this.events=new I(this.logger),this.store.set(N.APP_ID,e),this.store.set(N.TOKEN,t),this.config=s,this.version=new M,this.http=new R({baseURL:s.httpHost,developer:s.developer},{logger:this.logger,store:this.store}),this.generateTabId(),this.generateBrowserFingerprint(),this.listenBroadcastChannel()}setLogLevel(e){this.logger.setLogLevel(e)}async login(e){try{const t={...e||{}};if(t.userId&&!t.busiToken)return u(exports.ChatSdkErrorCode.SDK_ERROR,"Invalid param: userId and busiToken must be provided together");if(!t.userId){const e=this.store.browserFingerprint||await this.generateBrowserFingerprint();t.userId=e}const s=await this.innerRegister(t);if(!s.ok||!s.data)return this.logger.error("[InternalChatSdk] innerRegister failed",s),u(s.code,s.msg,s.msg_i18n);const r=s.data,i=await this.requestDeviceId(),n=await this.innerLogin(r,i,t);if(!n.ok||!n.data)return this.logger.error("[InternalChatSdk] innerLogin failed",n),u(n.code,n.msg,n.msg_i18n);const o=l.get("sessionid");if(!o)throw new Error("Login failed, not found sessionid");const a=n.data||{};return a.sessionId=o,a.secretKey=n.data.key,await Promise.all([this.syncLoginState(a),this.connectWebSocket(o)]),this.notifyOtherTabsLogin(),_({id:a.id,userId:t.userId,name:a.name,avatar:a.avatar,email:a.email})}catch(e){return this.handleException(e)}}innerRegister(e){return this.http.post("/open/user/register",{userID:e.userId,name:e.name,avatar:e.avatar,email:e.email,passWord:e.password,userBuf:e.userBuf,busiToken:e.busiToken})}innerLogin(e,t,s){return this.http.post("/open/user/login",{uid:e,busi_token:s.busiToken,device_id:t})}generateTabId(){const e=this.store.getWithSession(N.TAB_ID);if(e)return e;const t=`${this.store.appId}_${Date.now()}_${Math.random().toString(36).substring(2,15)}`;return this.store.setWithSession(N.TAB_ID,t),t}async generateBrowserFingerprint(){try{const e=this.store.getWithLocal(N.BROWSER_FINGERPRINT);if(e)return this.logger.debug("[ChatSdk] generateBrowserFingerprint success from localstorage",e),e;const t=await E.load(),s=await t.get();return this.logger.debug("[ChatSdk] generateBrowserFingerprint success",s.visitorId),this.store.setWithLocal(N.BROWSER_FINGERPRINT,s.visitorId),s.visitorId}catch(e){this.logger.info("[ChatSdk] FingerprintJS generateBrowserFingerprint Error",e);const t=`${Date.now()}_${Math.random().toString(36).substring(2,15)}`;return this.logger.debug("[ChatSdk] random generateBrowserFingerprint success",t),this.store.setWithLocal(N.BROWSER_FINGERPRINT,t),t}}async loadFeed(){const e=this.version.currentVersion;this.loadFeedAbortController&&this.loadFeedAbortController.abort(),this.loadFeedAbortController=new AbortController;const t=await this.http.get("/feed",{limit:10},{signal:this.loadFeedAbortController.signal}).catch(e=>{this.logger.error("[ChatSdk] loadFeed Error",e)});this.loadFeedAbortController=null;const s=this.version.check(e);if(!t||!s)return;const r=t.data?.feed_list?.find(e=>e.chat_type===exports.ChatType.groupChat);t.ok&&(this.logger.debug("[ChatSdk][FEED_UPDATED] loadFeed success",r),this.store.set(N.CURRENT_FEED,r),this.events.emit(exports.ChatSdkEvent.FEED_UPDATED,r))}async syncLoginState(e){this.store.set(N.CURRENT_USER,e),this.store.set(N.SDK_READY,!0),await this.loadFeed(),this.events.emit(exports.ChatSdkEvent.SDK_READY)}syncLogoutState(){this.unlistenBroadcastChannel(),this.store.set(N.CURRENT_USER,void 0),this.store.set(N.SDK_READY,!1),this.store.set(N.CURRENT_FEED,void 0),this.events.emit(exports.ChatSdkEvent.SDK_NOT_READY)}async requestDeviceId(){const e=this.store.getWithLocal(N.DEVICE_ID);if(e)return this.logger.debug("[ChatSdk] requestDeviceId success from localstorage",e),e;const t=await this.http.post("/device_api/device_id",{platform:"web",hash_str:this.store.browserFingerprint||""}).catch(e=>{this.logger.error("[ChatSdk] requestDeviceId Error",e)});if(t?.ok&&t?.data)return this.logger.debug("[ChatSdk] requestDeviceId success",t.data),this.store.setWithLocal(N.DEVICE_ID,t.data),t.data;if(this.store.browserFingerprint)return this.logger.debug("[ChatSdk] use browserFingerprint as deviceId",this.store.browserFingerprint),this.store.setWithLocal(N.DEVICE_ID,this.store.browserFingerprint),this.store.browserFingerprint;const s=`${Date.now()}_${Math.random().toString(36).substring(2,15)}`;return this.logger.debug("[ChatSdk] random generateDeviceId success",s),this.store.setWithLocal(N.DEVICE_ID,s),s}async logout(){try{if(!this.store.currentUser)return _(null);const e=await this.http.get("/user/logout");return e.ok?(this.syncLogoutState(),this.disconnectWebSocket(),_(null)):u(e.code,e.msg,e.msg_i18n)}catch(e){return this.handleException(e)}}async addGroupMember(e,t){try{if(this.assertReady(),!e)return u(exports.ChatSdkErrorCode.SDK_ERROR,"not found chat id");if(!t?.length)return _(null);const s=this.store.currentFeed;if(!s)return u(exports.ChatSdkErrorCode.SDK_ERROR,"not found current feed");const r=await this.getChatMembers(s.chat_id,s.chat_member);if(!r.ok)return u(r.code,r.msg,r.msg_i18n);const i=(r.data||[]).map(e=>e.user_id),n=t.filter(e=>!i.includes(e)),o=await this.addMember(n,s.chat_id);return o.ok?_(o.data):u(o.code,o.msg,o.msg_i18n)}catch(e){return this.handleException(e)}}async initialChat(e){try{this.assertReady();const t=this.store.currentFeed;if(!t){const t=await this.createFeed(e.receiverIds);return t.ok&&t.data?(this.store.set(N.CURRENT_FEED,t.data),_(t.data.chat_id)):u(t.code,t.msg,t.msg_i18n)}const s=await this.addGroupMember(t.chat_id,e.receiverIds);return s.ok?_(t.chat_id):s}catch(e){return this.handleException(e)}}async getCurrentFeed(){try{return this.assertReady(),{ok:!0,data:this.store.currentFeed}}catch(e){return this.handleException(e)}}async getMessageList(e){try{this.assertReady();const t=this.store.currentFeed;if(!t)return u(exports.ChatSdkErrorCode.SDK_ERROR,"No feed found");const{chat_id:s,first_position:r,last_message_position:i}=t,{positions:n,nextPosition:o,hasMore:a}=(e=>{const t=[];if(e.direction===exports.RequestDirection.up){let s=e.startPosition??e.maxPosition;for(;t.length<e.limit&&s>=e.minPosition;)t.push(s),s--;const r=s>=e.minPosition;let i;return r&&(i=s),{positions:t,nextPosition:i,hasMore:r}}{let s=e.startPosition??e.minPosition;for(;t.length<e.limit&&s<=e.maxPosition;)t.push(s),s++;const r=s<=e.maxPosition;let i;return r&&(i=s),{positions:t,nextPosition:i,hasMore:r}}})({maxPosition:i,minPosition:r,startPosition:e.messagePosition,limit:e.limit,direction:e.direction??exports.RequestDirection.up});if(n.length>0){const e=await this.http.post("/message/get_by_position",{chat_position:{[s]:n}});if(e.ok&&e.data?.[s]){return _({hasMore:a,list:e.data[s].reverse().filter(e=>e.message_kind_id!==exports.MessageKind.system&&e.operation!==exports.MessageOperation.recall),nextMessagePosition:o})}return u(e.code,e.msg,e.msg_i18n)}return _({hasMore:!1,list:[]})}catch(e){return this.handleException(e)}}async sendMessage(e){try{this.assertReady();const t=e.messageType;switch(t){case exports.MessageType.text:return this.sendTextMessage(e);case exports.MessageType.image:return this.sendImageMessage(e);case exports.MessageType.video:return this.sendVideoMessage(e);case exports.MessageType.file:return this.sendFileMessage(e);default:return this.logger.warn("Unsupported message type: ",t),u(exports.ChatSdkErrorCode.SDK_ERROR,`Unsupported message type: ${t}`)}}catch(e){return this.handleException(e)}}async sendTextMessage(e){return this.http.post("/message/send_text",{chat_id:e.chatId,client_msg_id:e.clientMsgId,text:e.text.trim()},{needSign:!0})}async sendImageMessage(e){return this.http.post("/message/send_image",{chat_id:e.chatId,client_msg_id:e.clientMsgId,object_url:e.objectUrl,width:e.width,height:e.height},{needSign:!0})}async sendVideoMessage(e){return this.http.post("/message/send_video",{chat_id:e.chatId,client_msg_id:e.clientMsgId,video_url:e.objectUrl,duration_second:e.duration,image_url:e.coverUrl,width:e.width,height:e.height},{needSign:!0})}async sendFileMessage(e){return this.http.post("/message/send_file",{chat_id:e.chatId,client_msg_id:e.clientMsgId,object_url:e.objectUrl,file_name:e.fileName,file_size:e.fileSize},{needSign:!0})}async uploadFile(e){const{chatId:t,fileContent:s,fileFormat:r,fileName:i,fileType:n,onUploadProgress:o}=e,a=new FormData;return a.append("file_content",s),a.append("file_type",n),a.append("file_name",i),a.append("file_format",r),a.append("chat_id",t),this.http.post("/chat/upload",a,{needSign:!1,ignoreDeveloper:!0,onUploadProgress:o,headers:{"Content-Type":"multipart/form-data"}})}async sendMessageReadReceipt(e){try{return this.assertReady(),e.messageIds?.length?this.http.post("/message/read",{chat_id:e.chatId,message_ids:e.messageIds},{needSign:!0}):_(null)}catch(e){return this.handleException(e)}}async markAllMessagesAsRead(e){const t=this.store.currentFeed?.unread_message_ids||[];return this.sendMessageReadReceipt({chatId:e,messageIds:t})}async recallMessage(e){try{return this.assertReady(),e.messageIds.length?this.http.post("/message/remove",{chat_id:e.chatId,message_ids:e.messageIds,two_way:1},{needSign:!0}):_(null)}catch(e){return this.handleException(e)}}async createFeed(e){return await this.http.post("/chat/group",{receiver_ids:e,group_type:0,name:`User ${this.store.currentUser?.name||this.store.currentUser?.id}`},{needSign:!0})}async getChatMembers(e,t){return this.http.post("/chat/chatter_info",JSON.stringify({chatters:{[e]:t}}))}async addMember(e,t){return t?e.length?this.http.post("/chat/group/add_member",{user_ids:e,chat_id:t},{needSign:!0}):_(null):u(exports.ChatSdkErrorCode.SDK_ERROR,"not found chat id")}handlePushMessage(e){switch(this.logger.debug("handlePushMessage",e),e.type){case t.CREATE_FEED:case t.UPDATE_FEED:this.handleFeedUpdate(e);break;case t.ADD_MESSAGE:this.handleAddMessage(e);break;case t.UPDATE_MESSAGE:this.handleUpdateMessage(e);break;case t.READ_MESSAGE:this.handleReadMessage(e);break;case t.KICK_OUT_DEVICE:this.handleKickOut()}}handleFeedUpdate(e){this.store.set(N.CURRENT_FEED,e.content),this.events.emit(exports.ChatSdkEvent.FEED_UPDATED,e.content)}async handleAddMessage(e){e.content.chat_id===this.store.currentChatId&&(await this.loadFeed(),this.events.emit(exports.ChatSdkEvent.MESSAGE_RECEIVED,e.content))}async handleUpdateMessage(e){e.content.chat_id===this.store.currentChatId&&(await this.loadFeed(),this.events.emit(exports.ChatSdkEvent.MESSAGE_UPDATED,e.content))}async handleReadMessage(e){e.content.chat_id===this.store.currentChatId&&(await this.loadFeed(),this.events.emit(exports.ChatSdkEvent.MESSAGE_RECEIPT_RECEIVED,{chatId:e.content.chat_id,messageIds:e.content.message_ids,readerUserIds:e.content.reader_ids}))}handleKickOut(){this.syncLogoutState(),this.disconnectWebSocket(),this.events.emit(exports.ChatSdkEvent.SDK_KICKOUT)}on(e,t){return this.events.on(e,t)}once(e,t){return this.events.once(e,t)}off(e,t){return this.events.off(e,t)}get currentUserId(){return this.logger.debug("[InternalChatSdk] get currentUserId==>",this.store.currentUser),this.store.currentUser?.id}get currentChatId(){return this.logger.debug("[InternalChatSdk] get currentChatId==>",this.store.currentChatId),this.store.currentChatId}get isReady(){return this.logger.debug("[InternalChatSdk] get isReady==>",this.store.ready),this.store.ready}listenBroadcastChannel(){new BroadcastChannel(k).onmessage=e=>{const t=this.store.appId,r=this.store.tabId;e.data.type===s.KICK_OUT&&e.data.appId===t&&e.data.tabId!==r&&(this.logger.debug("[BroadcastChannel] message: kick out",{appId:t,sourceTabId:e.data.tabId,currentTabId:r}),this.handleKickOut())}}unlistenBroadcastChannel(){new BroadcastChannel(k).close()}notifyOtherTabsLogin(){new BroadcastChannel(k).postMessage({type:s.KICK_OUT,appId:this.store.appId,tabId:this.store.tabId})}async connectWebSocket(e){if(!e)throw Error("connect websocket error, not found login user token");this.imClient=new U({token:e,wsUrl:`${this.config.websocketHost}/ws`},this.logger),this.imClient.on(O.OPEN,()=>{this.store.set(N.IS_CONNECTED,!0)}),this.imClient.on(O.KICK_OFF,()=>{this.store.set(N.IS_CONNECTED,!1)}),this.imClient.on(O.CLOSE,()=>{this.store.set(N.IS_CONNECTED,!1)}),this.imClient.on(O.MESSAGE,e=>{this.handlePushMessage(e)}),this.imClient.connect()}disconnectWebSocket(){this.imClient&&(this.imClient.disconnect(),this.imClient=null)}assertReady(){if(!this.store.ready)throw{code:exports.ChatSdkErrorCode.SDK_ERROR,msg:"sdk not ready"}}handleException(e){return this.logger.error("[ChatSDK Error]",e),{ok:!1,code:e.code||exports.ChatSdkErrorCode.SDK_ERROR,msg:e.msg||e.message||"sdk error"}}}const w=new Map;function F(e){return{setLogLevel(t){e.setLogLevel(t)},login:t=>e.login(t),logout:()=>e.logout(),initialChat:t=>e.initialChat(t),addGroupMember:(t,s)=>e.addGroupMember(t,s),getCurrentFeed:()=>e.getCurrentFeed(),getMessageList:t=>e.getMessageList(t),uploadFile:t=>e.uploadFile(t),sendMessage:t=>e.sendMessage(t),sendMessageReadReceipt:t=>e.sendMessageReadReceipt(t),markAllMessagesAsRead:t=>e.markAllMessagesAsRead(t),recallMessage:t=>e.recallMessage(t),get currentUserId(){return e.currentUserId},get currentChatId(){return e.currentChatId},get isReady(){return e.isReady},on:(t,s)=>e.on(t,s),once:(t,s)=>e.once(t,s),off:(t,s)=>e.off(t,s)}}var G={create:function(e,t,s){if(w.has(e))return F(w.get(e));const r=new v(e,t,s);return w.set(e,r),F(r)}};exports.default=G;
|