@mademi_dev/chatemi 1.0.1 → 1.0.2
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/chatemi.js +3 -5
- package/dist/chatemi.umd.cjs +1 -1
- package/package.json +1 -1
package/dist/chatemi.js
CHANGED
|
@@ -28,7 +28,7 @@ var d = {
|
|
|
28
28
|
config;
|
|
29
29
|
fetcher;
|
|
30
30
|
constructor(e) {
|
|
31
|
-
this.config = e, this.fetcher = e.fetchImpl ?? fetch;
|
|
31
|
+
this.config = e, this.fetcher = e.fetchImpl ?? ((e, t) => fetch(e, t));
|
|
32
32
|
}
|
|
33
33
|
async getMe(e) {
|
|
34
34
|
return this.request(this.endpoint("me"), { signal: e });
|
|
@@ -1502,10 +1502,8 @@ function Z({ className: e, title: t = "Messages", subtitle: n = "ChatEmi", place
|
|
|
1502
1502
|
y: 0
|
|
1503
1503
|
}), k = o(void 0), A = i(() => y.reduce((e, t) => e + (t.unreadCount ?? 0), 0), [y]), j = d ?? (w > 0 ? w : A);
|
|
1504
1504
|
function M() {
|
|
1505
|
-
|
|
1506
|
-
|
|
1507
|
-
return t && h && v.markNotificationsRead(), t && v.requestNotificationPermission(), t;
|
|
1508
|
-
});
|
|
1505
|
+
let e = !T;
|
|
1506
|
+
E(e), e && (h && v.markNotificationsRead(), v.requestNotificationPermission());
|
|
1509
1507
|
}
|
|
1510
1508
|
function P(e) {
|
|
1511
1509
|
e.target.closest("button") || (e.currentTarget.setPointerCapture(e.pointerId), k.current = {
|
package/dist/chatemi.umd.cjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
(function(e,t){typeof exports==`object`&&typeof module<`u`?t(exports,require("react"),require("react/jsx-runtime")):typeof define==`function`&&define.amd?define([`exports`,`react`,`react/jsx-runtime`],t):(e=typeof globalThis<`u`?globalThis:e||self,t(e.ChatEmi={},e.React,e.jsxRuntime))})(this,function(e,t,n){Object.defineProperty(e,Symbol.toStringTag,{value:`Module`});var r={me:`/me`,users:`/users`,user:e=>`/users/${encodeURIComponent(e)}`,conversations:`/conversations`,conversation:e=>`/conversations/${encodeURIComponent(e)}`,conversationAvatar:e=>`/conversations/${encodeURIComponent(e)}/avatar`,members:e=>`/conversations/${encodeURIComponent(e)}/members`,member:(e,t)=>`/conversations/${encodeURIComponent(e)}/members/${encodeURIComponent(t)}`,messages:e=>`/conversations/${encodeURIComponent(e)}/messages`,message:(e,t)=>`/conversations/${encodeURIComponent(e)}/messages/${encodeURIComponent(t)}`,markRead:e=>`/conversations/${encodeURIComponent(e)}/read`,markDelivered:e=>`/conversations/${encodeURIComponent(e)}/delivered`,forwardMessage:(e,t)=>`/conversations/${encodeURIComponent(e)}/messages/${encodeURIComponent(t)}/forward`,reactions:(e,t)=>`/conversations/${encodeURIComponent(e)}/messages/${encodeURIComponent(t)}/reactions`,upload:`/attachments`,search:`/search/messages`},i=class extends Error{status;payload;constructor(e,t,n){super(e),this.name=`ChatEmiApiError`,this.status=t,this.payload=n}},a=class{config;fetcher;constructor(e){this.config=e,this.fetcher=e.fetchImpl??fetch}async getMe(e){return this.request(this.endpoint(`me`),{signal:e})}async searchUsers(e,t){if(this.config.userDirectory){let n=this.config.userDirectory.searchPath??`/users`;return o(await this.request(n,{query:{q:e.query,cursor:e.cursor,limit:e.limit},signal:t,baseUrl:this.config.userDirectory.baseUrl,headers:await this.resolveUserDirectoryHeaders(),authorize:!1}),this.config.userDirectory.mapUser)}return this.request(this.endpoint(`users`),{query:{q:e.query,cursor:e.cursor,limit:e.limit},signal:t})}async getUser(e,t){if(this.config.userDirectory){let n=this.config.userDirectory.userPath?.(e)??`/users/${encodeURIComponent(e)}`,r=await this.request(n,{signal:t,baseUrl:this.config.userDirectory.baseUrl,headers:await this.resolveUserDirectoryHeaders(),authorize:!1});return this.config.userDirectory.mapUser?this.config.userDirectory.mapUser(r):r}return this.request(this.endpoint(`user`,e),{signal:t})}async listConversations(e={},t){return this.request(this.endpoint(`conversations`),{query:{...e},signal:t})}async getConversation(e,t){return this.request(this.endpoint(`conversation`,e),{signal:t})}async createConversation(e){return this.request(this.endpoint(`conversations`),{method:`POST`,body:e})}async createGroup(e){return this.createConversation({...e,type:`group`})}async createChannel(e){return this.createConversation({...e,type:`channel`,readOnly:e.readOnly??!0})}async updateConversation(e,t){return this.request(this.endpoint(`conversation`,e),{method:`PATCH`,body:t})}async archiveConversation(e){await this.request(this.endpoint(`conversation`,e),{method:`DELETE`})}async updateConversationAvatar(e){if(e.conversationId)return this.request(this.endpoint(`conversationAvatar`,e.conversationId),{method:`PATCH`,body:{attachment:e.attachment}});if(!e.userId)throw Error(`ChatEmi avatar update requires conversationId or userId`);return this.request(this.endpoint(`user`,e.userId),{method:`PATCH`,body:{avatar:e.attachment}})}async addMembers(e,t){return this.request(this.endpoint(`members`,e),{method:`POST`,body:{userIds:t}})}async updateMember(e){return this.request(this.endpoint(`member`,e.conversationId,e.userId),{method:`PATCH`,body:e})}async removeMember(e){await this.request(this.endpoint(`member`,e.conversationId,e.userId),{method:`DELETE`})}async listMessages(e,t={},n){return this.request(this.endpoint(`messages`,e),{query:{...t},signal:n})}async sendMessage(e){return this.request(this.endpoint(`messages`,e.conversationId),{method:`POST`,body:e})}async forwardMessage(e){return this.request(this.endpoint(`forwardMessage`,e.sourceConversationId,e.messageId),{method:`POST`,body:e})}async editMessage(e){return this.request(this.endpoint(`message`,e.conversationId,e.messageId),{method:`PATCH`,body:e})}async deleteMessage(e,t){await this.request(this.endpoint(`message`,e,t),{method:`DELETE`})}async markConversationRead(e,t){await this.request(this.endpoint(`markRead`,e),{method:`POST`,body:{messageIds:t}})}async markConversationDelivered(e,t){await this.request(this.endpoint(`markDelivered`,e),{method:`POST`,body:{messageIds:t}})}async addReaction(e,t,n){return this.request(this.endpoint(`reactions`,e,t),{method:`POST`,body:{emoji:n}})}async removeReaction(e,t,n){return this.request(this.endpoint(`reactions`,e,t),{method:`DELETE`,body:{emoji:n}})}async uploadAttachment(e){let t=new FormData;return t.append(`file`,e.file,e.name),e.conversationId&&t.append(`conversationId`,e.conversationId),e.type&&t.append(`type`,e.type),e.metadata&&t.append(`metadata`,JSON.stringify(e.metadata)),this.request(this.endpoint(`upload`),{method:`POST`,body:t})}async searchMessages(e,t={},n){return this.request(this.endpoint(`search`),{query:{q:e,...t},signal:n})}endpoint(e,t,n){switch(e){case`user`:case`conversation`:case`conversationAvatar`:case`members`:case`messages`:case`markRead`:case`markDelivered`:return(this.config.endpoints?.[e]??r[e])(t??``);case`member`:case`message`:case`forwardMessage`:case`reactions`:return(this.config.endpoints?.[e]??r[e])(t??``,n??``);default:return this.config.endpoints?.[e]??r[e]}}async request(e,t={}){let n=this.buildUrl(e,t.query,t.baseUrl),r=new Headers(await this.resolveHeaders(t.headers,t.authorize??!0)),a=typeof FormData<`u`&&t.body instanceof FormData;!a&&t.body!==void 0&&!r.has(`Content-Type`)&&r.set(`Content-Type`,`application/json`);let o=await this.fetcher(n,{method:t.method??`GET`,headers:r,body:a?t.body:t.body===void 0?void 0:JSON.stringify(t.body),signal:t.signal});if(o.status===204)return;let s=await this.parseResponse(o);if(!o.ok)throw new i(this.errorMessage(s,o.status),o.status,s);return s}buildUrl(e,t,n=this.config.apiBaseUrl){let r=/^https?:\/\//i.test(e),i=n.replace(/\/+$/,``),a=e.startsWith(`/`)?e:`/${e}`,o=new URL(r?e:`${i}${a}`);return Object.entries(t??{}).forEach(([e,t])=>{t!=null&&t!==``&&o.searchParams.set(e,String(t))}),o.toString()}async resolveHeaders(e,t=!0){let n=new Headers,r=typeof this.config.headers==`function`?await this.config.headers():this.config.headers,i=typeof this.config.token==`function`?await this.config.token():this.config.token;return new Headers(r).forEach((e,t)=>n.set(t,e)),new Headers(e).forEach((e,t)=>n.set(t,e)),t&&i&&!n.has(`Authorization`)&&n.set(`Authorization`,`Bearer ${i}`),n}async resolveUserDirectoryHeaders(){return(typeof this.config.userDirectory?.headers==`function`?await this.config.userDirectory.headers():this.config.userDirectory?.headers)??{}}async parseResponse(e){return(e.headers.get(`Content-Type`)??``).includes(`application/json`)?e.json():e.text()}errorMessage(e,t){return e&&typeof e==`object`&&`message`in e&&typeof e.message==`string`?e.message:`ChatEmi API request failed with status ${t}`}};function o(e,t){let n=e=>t?t(e):e;return Array.isArray(e)?{items:e.map(n)}:{...e,items:e.items.map(n)}}var s=500,c=8e3,l=1/0,u=class{config;socket;reconnectAttempts=0;shouldReconnect=!0;reconnectTimer;queue=[];listeners=new Map;constructor(e){this.config=e}get readyState(){return this.socket?.readyState}async connect(){this.config.socketUrl&&(this.socket?.readyState===WebSocket.OPEN||this.socket?.readyState===WebSocket.CONNECTING||(this.shouldReconnect=this.config.reconnect?.enabled??!0,this.createSocket(await this.buildSocketUrl())))}disconnect(){this.shouldReconnect=!1,this.clearReconnectTimer(),this.socket?.close(),this.socket=void 0}on(e,t){let n=this.listeners.get(e)??new Set;return n.add(t),this.listeners.set(e,n),()=>{n.delete(t),n.size===0&&this.listeners.delete(e)}}send(e,t,n){let r={type:e,payload:t,requestId:n};if(this.socket?.readyState===WebSocket.OPEN){this.socket.send(JSON.stringify(r));return}this.queue.push(r)}subscribeConversation(e){this.send(`conversation.subscribe`,{conversationId:e})}unsubscribeConversation(e){this.send(`conversation.unsubscribe`,{conversationId:e})}sendTyping(e,t){this.send(`typing`,{conversationId:e,isTyping:t})}sendReadReceipt(e,t){this.send(`message.read`,{conversationId:e,messageIds:t})}sendDeliveredReceipt(e,t){this.send(`message.delivered`,{conversationId:e,messageIds:t})}sendForward(e){this.send(`message.forward`,e)}sendMemberUpdate(e){this.send(`conversation.member.update`,e)}sendAvatarUpdate(e){this.send(`conversation.avatar.update`,{conversationId:e})}sendPresence(e){this.send(`presence`,{status:e})}createSocket(e){let t=(this.config.websocketFactory??(e=>new WebSocket(e)))(e);this.socket=t,t.addEventListener(`open`,()=>{this.reconnectAttempts=0,this.dispatch(`connected`,void 0),this.flushQueue()}),t.addEventListener(`close`,e=>{this.dispatch(`disconnected`,e),this.socket=void 0,this.scheduleReconnect()}),t.addEventListener(`error`,e=>{this.dispatch(`error`,e)}),t.addEventListener(`message`,e=>{this.handleMessage(e.data)})}handleMessage(e){try{let t=typeof e==`string`?JSON.parse(e):e;t&&typeof t.type==`string`&&this.dispatchRaw(t.type,t.payload)}catch(e){this.dispatch(`error`,e instanceof Error?e:Error(`Unable to parse ChatEmi socket message`))}}flushQueue(){for(;this.queue.length>0&&this.socket?.readyState===WebSocket.OPEN;){let e=this.queue.shift();e&&this.socket.send(JSON.stringify(e))}}scheduleReconnect(){if(!this.shouldReconnect||!this.config.socketUrl)return;let e=this.config.reconnect?.maxAttempts??l;if(this.reconnectAttempts>=e)return;this.reconnectAttempts+=1;let t=this.config.reconnect?.initialDelayMs??s,n=this.config.reconnect?.maxDelayMs??c,r=Math.min(t*2**(this.reconnectAttempts-1),n);this.dispatch(`reconnecting`,{attempt:this.reconnectAttempts,delay:r}),this.clearReconnectTimer(),this.reconnectTimer=setTimeout(()=>{this.connect()},r)}async buildSocketUrl(){let e=this.config.socketUrl;if(!e)throw Error(`ChatEmi socketUrl is required before connecting the socket`);let t=new URL(e),n=typeof this.config.token==`function`?await this.config.token():this.config.token;return n&&t.searchParams.set(`token`,n),t.toString()}dispatch(e,t){this.listeners.get(e)?.forEach(e=>e(t))}dispatchRaw(e,t){this.listeners.get(e)?.forEach(e=>e(t))}clearReconnectTimer(){this.reconnectTimer&&=(clearTimeout(this.reconnectTimer),void 0)}},d=(0,t.createContext)(void 0);function f(e,t=[],n,r=[]){return{currentUser:e.currentUser,conversations:t,activeConversationId:n??t[0]?.id,messagesByConversation:{},typingByConversation:{},presenceByUser:{},notifications:r,unreadNotificationCount:r.filter(e=>!e.read).length,connectionStatus:`idle`,theme:e.theme??`light`,loading:!1}}function p(e,t){switch(t.type){case`set-loading`:return{...e,loading:t.loading};case`set-error`:return{...e,error:t.error};case`set-connection-status`:return{...e,connectionStatus:t.status};case`set-current-user`:return{...e,currentUser:t.user};case`set-conversations`:return{...e,conversations:b(t.conversations),activeConversationId:e.activeConversationId??t.conversations[0]?.id};case`upsert-conversation`:return{...e,conversations:b(g(e.conversations,t.conversation))};case`remove-conversation`:return{...e,conversations:e.conversations.filter(e=>e.id!==t.conversationId),activeConversationId:e.activeConversationId===t.conversationId?void 0:e.activeConversationId};case`upsert-member`:return{...e,conversations:e.conversations.map(e=>e.id===t.conversationId?{...e,members:_(e.members??[],t.member),participants:g(e.participants,t.member.user)}:e)};case`remove-member`:return{...e,conversations:e.conversations.map(e=>e.id===t.conversationId?{...e,members:(e.members??[]).filter(e=>e.user.id!==t.userId),participants:e.participants.filter(e=>e.id!==t.userId)}:e)};case`set-active-conversation`:return{...e,activeConversationId:t.conversationId};case`set-messages`:return{...e,messagesByConversation:{...e.messagesByConversation,[t.conversationId]:x(t.messages)}};case`upsert-message`:{let n=e.messagesByConversation[t.message.conversationId]??[],r=S(e.conversations,t.message);return{...e,conversations:r,messagesByConversation:{...e.messagesByConversation,[t.message.conversationId]:x(g(n,t.message))}}}case`remove-message`:return{...e,messagesByConversation:{...e.messagesByConversation,[t.conversationId]:(e.messagesByConversation[t.conversationId]??[]).filter(e=>e.id!==t.messageId)}};case`set-message-reactions`:return{...e,messagesByConversation:{...e.messagesByConversation,[t.conversationId]:(e.messagesByConversation[t.conversationId]??[]).map(e=>e.id===t.messageId?{...e,reactions:t.reactions}:e)}};case`apply-receipt`:return{...e,messagesByConversation:{...e.messagesByConversation,[t.receipt.conversationId]:(e.messagesByConversation[t.receipt.conversationId]??[]).map(e=>t.receipt.messageIds.includes(e.id)?v(e,t.receipt):e)}};case`add-notification`:{let n=(e.notifications.some(e=>e.id===t.notification.id)?e.notifications.map(e=>e.id===t.notification.id?t.notification:e):[t.notification,...e.notifications]).slice(0,t.maxStored??50);return{...e,notifications:n,unreadNotificationCount:n.filter(e=>!e.read).length}}case`dismiss-notification`:{let n=e.notifications.filter(e=>e.id!==t.notificationId);return{...e,notifications:n,unreadNotificationCount:n.filter(e=>!e.read).length}}case`mark-notifications-read`:{let n=t.notificationIds?new Set(t.notificationIds):void 0,r=e.notifications.map(e=>!n||n.has(e.id)?{...e,read:!0}:e);return{...e,notifications:r,unreadNotificationCount:r.filter(e=>!e.read).length}}case`clear-notifications`:return{...e,notifications:[],unreadNotificationCount:0};case`set-typing`:{let n=(e.typingByConversation[t.event.conversationId]??[]).filter(e=>e.user.id!==t.event.user.id);return{...e,typingByConversation:{...e.typingByConversation,[t.event.conversationId]:t.event.isTyping?[...n,t.event]:n}}}case`set-presence`:return{...e,presenceByUser:{...e.presenceByUser,[t.userId]:{userId:t.userId,status:t.status,lastSeenAt:t.lastSeenAt}}};default:return e}}function m({children:e,config:r,autoConnect:i=!0,initialConversations:o,initialActiveConversationId:s,initialNotifications:c}){let l=(0,t.useMemo)(()=>new a(r),[r]),m=(0,t.useMemo)(()=>new u(r),[r]),h=(0,t.useRef)({activeConversationId:s,currentUserId:r.currentUser?.id}),g=(0,t.useRef)(new Set),[_,v]=(0,t.useReducer)(p,f(r,o,s,c));(0,t.useEffect)(()=>{h.current={activeConversationId:_.activeConversationId,currentUserId:_.currentUser?.id}},[_.activeConversationId,_.currentUser?.id]),(0,t.useEffect)(()=>{let e=!0,t=new AbortController;v({type:`set-current-user`,user:r.currentUser});async function n(){v({type:`set-loading`,loading:!0}),v({type:`set-error`,error:void 0});try{let[n,i]=await Promise.all([r.currentUser?Promise.resolve(r.currentUser):l.getMe(t.signal).catch(()=>void 0),l.listConversations({},t.signal)]);if(!e)return;v({type:`set-current-user`,user:n}),v({type:`set-conversations`,conversations:i.items})}catch(t){e&&v({type:`set-error`,error:w(t)})}finally{e&&v({type:`set-loading`,loading:!1})}}return n(),()=>{e=!1,t.abort()}},[l,r.currentUser]),(0,t.useEffect)(()=>{let e=[m.on(`connected`,()=>v({type:`set-connection-status`,status:`connected`})),m.on(`disconnected`,()=>v({type:`set-connection-status`,status:`disconnected`})),m.on(`reconnecting`,()=>v({type:`set-connection-status`,status:`reconnecting`})),m.on(`error`,e=>{v({type:`set-connection-status`,status:`error`}),v({type:`set-error`,error:w(e)})}),m.on(`conversation.created`,e=>v({type:`upsert-conversation`,conversation:e})),m.on(`conversation.updated`,e=>v({type:`upsert-conversation`,conversation:e})),m.on(`conversation.deleted`,({conversationId:e})=>v({type:`remove-conversation`,conversationId:e})),m.on(`conversation.member.added`,({conversationId:e,member:t})=>v({type:`upsert-member`,conversationId:e,member:t})),m.on(`conversation.member.updated`,({conversationId:e,member:t})=>v({type:`upsert-member`,conversationId:e,member:t})),m.on(`conversation.member.removed`,({conversationId:e,userId:t})=>v({type:`remove-member`,conversationId:e,userId:t})),m.on(`message.created`,e=>{v({type:`upsert-message`,message:e}),e.sender.id!==h.current.currentUserId&&v({type:`add-notification`,notification:C(e),maxStored:r.notifications?.maxStored})}),m.on(`message.updated`,e=>v({type:`upsert-message`,message:e})),m.on(`message.deleted`,({conversationId:e,messageId:t})=>v({type:`remove-message`,conversationId:e,messageId:t})),m.on(`message.receipt`,e=>v({type:`apply-receipt`,receipt:e})),m.on(`message.reaction`,({conversationId:e,messageId:t,reactions:n})=>v({type:`set-message-reactions`,conversationId:e,messageId:t,reactions:n})),m.on(`typing`,e=>v({type:`set-typing`,event:e})),m.on(`presence`,({userId:e,status:t,lastSeenAt:n})=>v({type:`set-presence`,userId:e,status:t,lastSeenAt:n})),m.on(`notification`,e=>v({type:`add-notification`,notification:e,maxStored:r.notifications?.maxStored}))];return i&&r.socketUrl&&(v({type:`set-connection-status`,status:`connecting`}),m.connect()),()=>{e.forEach(e=>e()),m.disconnect()}},[i,r.notifications?.maxStored,r.socketUrl,m]),(0,t.useEffect)(()=>{!r.notifications?.enabled||!r.notifications.browser||typeof window>`u`||!(`Notification`in window)||window.Notification.permission!==`granted`||(r.notifications.showWhenOpen||typeof document>`u`||document.hidden)&&_.notifications.forEach(e=>{e.read||g.current.has(e.id)||(g.current.add(e.id),new window.Notification(e.title||r.notifications?.title||`New message`,{body:e.body,icon:e.avatarUrl}))})},[r.notifications,_.notifications]);let y=(0,t.useCallback)(async(e={})=>{v({type:`set-loading`,loading:!0});try{let t=await l.listConversations(e);return v({type:`set-conversations`,conversations:t.items}),t.items}finally{v({type:`set-loading`,loading:!1})}},[l]),b=(0,t.useCallback)(async(e,t={})=>{v({type:`set-active-conversation`,conversationId:e}),m.subscribeConversation(e);let n=await l.listMessages(e,t);return v({type:`set-messages`,conversationId:e,messages:n.items}),l.markConversationDelivered(e,n.items.filter(e=>e.sender.id!==_.currentUser?.id).map(e=>e.id)),n.items},[l,m,_.currentUser?.id]),x=(0,t.useCallback)(async e=>{let t=await l.createConversation(e);return v({type:`upsert-conversation`,conversation:t}),v({type:`set-active-conversation`,conversationId:t.id}),t},[l]),S=(0,t.useCallback)(async e=>{let t=`temp-${Date.now()}`,n=_.currentUser?{id:t,conversationId:e.conversationId,sender:_.currentUser,text:e.text,html:e.html,attachments:e.attachments,kind:e.kind,replyToId:e.replyToId,status:`sending`,createdAt:new Date().toISOString(),metadata:e.metadata}:void 0;n&&v({type:`upsert-message`,message:n});try{let r=await l.sendMessage(e);return n&&v({type:`remove-message`,conversationId:e.conversationId,messageId:t}),v({type:`upsert-message`,message:r}),r}catch(e){throw n&&v({type:`upsert-message`,message:{...n,status:`failed`}}),e}},[l,_.currentUser]),T=(0,t.useCallback)(async e=>{let t=await l.editMessage(e);return v({type:`upsert-message`,message:t}),t},[l]),E=(0,t.useCallback)(async(e,t)=>{await l.deleteMessage(e,t),v({type:`remove-message`,conversationId:e,messageId:t})},[l]),D=(0,t.useCallback)(async(e,t)=>{await l.markConversationRead(e,t),m.sendReadReceipt(e,t??[])},[l,m]),O=(0,t.useCallback)(async(e,t)=>{await l.markConversationDelivered(e,t),m.sendDeliveredReceipt(e,t??[])},[l,m]),k=(0,t.useCallback)(async e=>{let t=await l.forwardMessage(e);return m.sendForward(e),v({type:`upsert-message`,message:t}),t},[l,m]),A=(0,t.useCallback)(async(e,t,n)=>{let r=await l.addReaction(e,t,n);return v({type:`upsert-message`,message:r}),r},[l]),j=(0,t.useCallback)(async(e,t,n)=>{let r=await l.removeReaction(e,t,n);return v({type:`upsert-message`,message:r}),r},[l]),M=(0,t.useCallback)(e=>l.uploadAttachment(e),[l]),N=(0,t.useCallback)(async e=>{let t=await l.updateConversationAvatar(e);return`participants`in t?(v({type:`upsert-conversation`,conversation:t}),m.sendAvatarUpdate(t.id)):v({type:`set-current-user`,user:_.currentUser?.id===t.id?t:_.currentUser}),t},[l,m,_.currentUser]),P=(0,t.useCallback)(async(e,t)=>{let n=await l.addMembers(e,t);return n.forEach(t=>v({type:`upsert-member`,conversationId:e,member:t})),n},[l]),F=(0,t.useCallback)(async e=>{let t=await l.updateMember(e);return v({type:`upsert-member`,conversationId:e.conversationId,member:t}),m.sendMemberUpdate(e),t},[l,m]),I=(0,t.useCallback)(async e=>{await l.removeMember(e),v({type:`remove-member`,conversationId:e.conversationId,userId:e.userId})},[l]),L=(0,t.useCallback)(async e=>(await l.searchUsers(e)).items,[l]),R=(0,t.useCallback)(async(e,t={})=>(await l.searchMessages(e,t)).items,[l]),z=(0,t.useCallback)(e=>m.sendTyping(e,!0),[m]),B=(0,t.useCallback)(e=>m.sendTyping(e,!1),[m]),V=(0,t.useCallback)(e=>m.sendPresence(e),[m]),H=(0,t.useCallback)(e=>{v({type:`dismiss-notification`,notificationId:e})},[]),U=(0,t.useCallback)(e=>{v({type:`mark-notifications-read`,notificationIds:e})},[]),W=(0,t.useCallback)(()=>{v({type:`clear-notifications`})},[]),G=(0,t.useCallback)(async()=>typeof window>`u`||!(`Notification`in window)?`unsupported`:window.Notification.permission===`granted`||window.Notification.permission===`denied`?window.Notification.permission:window.Notification.requestPermission(),[]),K=(0,t.useCallback)(()=>m.connect(),[m]),q=(0,t.useCallback)(()=>m.disconnect(),[m]),J=(0,t.useMemo)(()=>({refreshConversations:y,openConversation:b,createConversation:x,sendMessage:S,editMessage:T,deleteMessage:E,markRead:D,markDelivered:O,forwardMessage:k,addReaction:A,removeReaction:j,uploadAttachment:M,updateAvatar:N,addMembers:P,updateMember:F,removeMember:I,searchUsers:L,searchMessages:R,startTyping:z,stopTyping:B,setPresence:V,dismissNotification:H,markNotificationsRead:U,clearNotifications:W,requestNotificationPermission:G,connect:K,disconnect:q}),[y,b,x,S,T,E,D,O,k,A,j,M,N,P,F,I,L,R,z,B,V,H,U,W,G,K,q]),Y=_.conversations.find(e=>e.id===_.activeConversationId),X=_.activeConversationId?_.messagesByConversation[_.activeConversationId]??[]:[],Z=(0,t.useMemo)(()=>({..._,api:l,socket:m,activeConversation:Y,activeMessages:X,actions:J}),[J,Y,X,l,m,_]);return(0,n.jsx)(d.Provider,{value:Z,children:e})}function h(){let e=(0,t.useContext)(d);if(!e)throw Error(`useChatEmi must be used inside a ChatEmiProvider`);return e}function g(e,t){let n=e.findIndex(e=>e.id===t.id);return n===-1?[...e,t]:[...e.slice(0,n),t,...e.slice(n+1)]}function _(e,t){let n=e.findIndex(e=>e.user.id===t.user.id);return n===-1?[...e,t]:[...e.slice(0,n),t,...e.slice(n+1)]}function v(e,t){let n=t.status===`read`?`readBy`:`deliveredTo`,r=y(e[n]??[],t);return{...e,[n]:r,status:t.status===`read`||e.status===`read`?`read`:`delivered`}}function y(e,t){let n=e.findIndex(e=>e.userId===t.userId&&e.status===t.status);return n===-1?[...e,t]:[...e.slice(0,n),t,...e.slice(n+1)]}function b(e){return[...e].sort((e,t)=>{let n=e.lastMessage?.createdAt??e.updatedAt??e.createdAt,r=t.lastMessage?.createdAt??t.updatedAt??t.createdAt;return Date.parse(r)-Date.parse(n)})}function x(e){return[...e].sort((e,t)=>Date.parse(e.createdAt)-Date.parse(t.createdAt))}function S(e,t){return b(e.map(e=>e.id===t.conversationId?{...e,lastMessage:t,updatedAt:t.createdAt}:e))}function C(e){return{id:`message:${e.id}`,kind:`message`,title:e.sender.name,body:e.text??e.attachments?.[0]?.name??`Sent a message`,conversationId:e.conversationId,messageId:e.id,actor:e.sender,avatarUrl:e.sender.avatarUrl,read:!1,createdAt:e.createdAt,metadata:e.metadata}}function w(e){return e instanceof Error?e.message:`Unexpected ChatEmi error`}function T({className:e,emptyState:r,composerPlaceholder:i=`Write a message...`,showSidebar:a=!0,theme:o,enableAdminControls:s=!0,enableMessageActions:c=!0,enableMediaPreview:l=!0,renderConversation:u,renderMessage:d}){let{actions:f,activeConversation:p,activeMessages:m,connectionStatus:g,conversations:_,currentUser:v,error:y,loading:b,theme:x,typingByConversation:S}=h(),[C,w]=(0,t.useState)(``),[T,O]=(0,t.useState)(``),[N,P]=(0,t.useState)(``),[F,z]=(0,t.useState)([]),[B,V]=(0,t.useState)(!1),[H,U]=(0,t.useState)(),[W,G]=(0,t.useState)([]),[K,q]=(0,t.useState)(!1),J=(0,t.useRef)(void 0),Y=o??x,X=(0,t.useMemo)(()=>{let e=T.trim().toLowerCase();return e?_.filter(t=>A(t,v?.id).toLowerCase().includes(e)):_},[_,v?.id,T]),Z=p?S[p.id]??[]:[],Q=(0,t.useMemo)(()=>m.map(e=>e.id).join(`,`),[m]),$=p?.members?.find(e=>e.user.id===v?.id),ee=s&&!!($&&[`owner`,`admin`,`moderator`].includes($.role));(0,t.useEffect)(()=>{if(!p||!Q)return;let e=m.filter(e=>e.sender.id!==v?.id).map(e=>e.id);e.length>0&&f.markRead(p.id,e)},[f,p,m,v?.id,Q]),(0,t.useEffect)(()=>{let e=!0;async function t(){if(N.trim().length<2){z([]);return}let t=await f.searchUsers({query:N.trim(),limit:8});e&&z(t)}return t(),()=>{e=!1}},[f,N]);async function te(e){if(e.preventDefault(),!p||!C.trim()&&W.length===0)return;let t=C.trim(),n=W;w(``),G([]),f.stopTyping(p.id);try{await f.sendMessage({conversationId:p.id,text:t||void 0,attachments:n.length>0?n:void 0,kind:L(n),replyToId:H?.id}),U(void 0)}catch{w(t),G(n)}}async function ne(e){if(e?.length){q(!0);try{let t=await Promise.all(Array.from(e).map(e=>f.uploadAttachment({file:e,name:e.name,type:I(e)})));G(e=>[...e,...t])}finally{q(!1)}}}function re(e){w(e),p&&(f.startTyping(p.id),J.current&&clearTimeout(J.current),J.current=setTimeout(()=>f.stopTyping(p.id),1400))}return(0,n.jsxs)(`section`,{className:[`chatemi`,e].filter(Boolean).join(` `),"data-status":g,"data-theme":Y,children:[a?(0,n.jsxs)(`aside`,{className:`chatemi__sidebar`,"aria-label":`Conversations`,children:[(0,n.jsxs)(`div`,{className:`chatemi__brand`,children:[(0,n.jsxs)(`div`,{children:[(0,n.jsx)(`strong`,{children:`ChatEmi`}),(0,n.jsx)(`span`,{children:M(g)})]}),(0,n.jsx)(`span`,{className:`chatemi__status chatemi__status--${g}`})]}),(0,n.jsxs)(`label`,{className:`chatemi__search`,children:[(0,n.jsx)(`span`,{className:`chatemi__sr-only`,children:`Search conversations`}),(0,n.jsx)(`input`,{value:T,onChange:e=>O(e.target.value),placeholder:`Search chats`})]}),(0,n.jsx)(`div`,{className:`chatemi__conversation-list`,children:X.map(e=>{let t=e.id===p?.id;return(0,n.jsx)(`button`,{className:`chatemi__conversation ${t?`chatemi__conversation--active`:``}`,onClick:()=>void f.openConversation(e.id),type:`button`,children:u?u(e,t):(0,n.jsx)(E,{conversation:e,currentUserId:v?.id})},e.id)})})]}):null,(0,n.jsxs)(`main`,{className:`chatemi__main`,children:[p?(0,n.jsxs)(n.Fragment,{children:[(0,n.jsxs)(`header`,{className:`chatemi__header`,children:[(0,n.jsx)(k,{conversation:p,currentUserId:v?.id}),(0,n.jsxs)(`div`,{children:[(0,n.jsx)(`strong`,{children:A(p,v?.id)}),(0,n.jsx)(`span`,{children:Z.length>0?`${Z.map(e=>e.user.name).join(`, `)} typing...`:j(p,v?.id)})]}),ee?(0,n.jsx)(`button`,{className:`chatemi__header-action`,onClick:()=>V(e=>!e),type:`button`,children:`Members`}):null]}),B&&p?(0,n.jsxs)(`section`,{className:`chatemi__members`,"aria-label":`Member management`,children:[(0,n.jsx)(`div`,{className:`chatemi__members-list`,children:(p.members??p.participants.map(e=>R(e))).map(e=>(0,n.jsxs)(`div`,{className:`chatemi__member`,children:[e.user.avatarUrl?(0,n.jsx)(`img`,{alt:``,className:`chatemi__member-avatar`,src:e.user.avatarUrl}):(0,n.jsx)(`span`,{className:`chatemi__member-avatar`,children:e.user.name.slice(0,2).toUpperCase()}),(0,n.jsxs)(`span`,{children:[(0,n.jsx)(`strong`,{children:e.user.name}),(0,n.jsx)(`small`,{children:e.role})]}),e.role!==`owner`&&e.user.id!==v?.id?(0,n.jsxs)(`span`,{className:`chatemi__member-actions`,children:[(0,n.jsx)(`button`,{onClick:()=>void f.updateMember({conversationId:p.id,userId:e.user.id,role:`admin`}),type:`button`,children:`Admin`}),(0,n.jsx)(`button`,{onClick:()=>void f.updateMember({conversationId:p.id,userId:e.user.id,role:`member`}),type:`button`,children:`Member`}),(0,n.jsx)(`button`,{onClick:()=>void f.removeMember({conversationId:p.id,userId:e.user.id}),type:`button`,children:`Remove`})]}):null]},e.user.id))}),(0,n.jsxs)(`label`,{className:`chatemi__member-search`,children:[(0,n.jsx)(`span`,{children:`Find users from external directory`}),(0,n.jsx)(`input`,{onChange:e=>P(e.target.value),placeholder:`Search users`,value:N})]}),F.length>0?(0,n.jsx)(`div`,{className:`chatemi__user-results`,children:F.map(e=>(0,n.jsxs)(`button`,{onClick:()=>void f.addMembers(p.id,[e.id]),type:`button`,children:[e.avatarUrl?(0,n.jsx)(`img`,{alt:``,src:e.avatarUrl}):null,`Add `,e.name]},e.id))}):null]}):null,(0,n.jsxs)(`div`,{className:`chatemi__messages`,role:`log`,"aria-live":`polite`,children:[m.map(e=>{let t=e.sender.id===v?.id;return d?(0,n.jsx)(`div`,{className:`chatemi__message-shell`,children:d(e,t)},e.id):(0,n.jsx)(D,{enableActions:c,enableMediaPreview:l,isMine:t,message:e,onForward:e=>{let t=window.prompt(`Forward to conversation id`);t&&f.forwardMessage({sourceConversationId:e.conversationId,targetConversationId:t,messageId:e.id})},onReply:U},e.id)}),m.length===0&&!b?(0,n.jsx)(`div`,{className:`chatemi__empty`,children:`No messages yet. Start the conversation.`}):null]}),W.length>0?(0,n.jsx)(`div`,{className:`chatemi__attachments`,children:W.map(e=>(0,n.jsx)(`button`,{className:`chatemi__attachment-pill`,onClick:()=>G(t=>t.filter(t=>t.id!==e.id)),type:`button`,children:e.name??e.type},e.id))}):null,H?(0,n.jsxs)(`div`,{className:`chatemi__replying`,children:[(0,n.jsxs)(`span`,{children:[`Replying to `,(0,n.jsx)(`strong`,{children:H.sender.name}),`: `,H.text??H.attachments?.[0]?.name??`media`]}),(0,n.jsx)(`button`,{onClick:()=>U(void 0),type:`button`,children:`Cancel`})]}):null,(0,n.jsxs)(`form`,{className:`chatemi__composer`,onSubmit:e=>void te(e),children:[(0,n.jsxs)(`label`,{className:`chatemi__upload`,children:[(0,n.jsx)(`span`,{children:K?`Uploading`:`Attach`}),(0,n.jsx)(`input`,{disabled:K,multiple:!0,onChange:e=>void ne(e.target.files),type:`file`})]}),(0,n.jsx)(`textarea`,{onBlur:()=>f.stopTyping(p.id),onChange:e=>re(e.target.value),placeholder:i,rows:1,value:C}),(0,n.jsx)(`button`,{disabled:K||!C.trim()&&W.length===0,type:`submit`,children:`Send`})]})]}):r??(0,n.jsx)(`div`,{className:`chatemi__empty chatemi__empty--screen`,children:`Select a conversation to start messaging.`}),y?(0,n.jsx)(`div`,{className:`chatemi__error`,children:y}):null]})]})}function E({conversation:e,currentUserId:t}){return(0,n.jsxs)(n.Fragment,{children:[(0,n.jsx)(k,{conversation:e,currentUserId:t}),(0,n.jsxs)(`span`,{className:`chatemi__conversation-body`,children:[(0,n.jsx)(`strong`,{children:A(e,t)}),(0,n.jsx)(`small`,{children:e.lastMessage?.text??e.description??`No messages yet`})]}),e.unreadCount?(0,n.jsx)(`span`,{className:`chatemi__badge`,children:e.unreadCount}):null]})}function D({message:e,isMine:t,enableActions:r,enableMediaPreview:i,onReply:a,onForward:o}){return(0,n.jsxs)(`article`,{className:`chatemi__message ${t?`chatemi__message--mine`:``}`,children:[t?null:(0,n.jsx)(`strong`,{className:`chatemi__message-sender`,children:e.sender.name}),e.forwardedFrom?(0,n.jsxs)(`div`,{className:`chatemi__forwarded`,children:[`Forwarded from `,e.forwardedFrom.name]}):null,e.replyTo?(0,n.jsxs)(`blockquote`,{className:`chatemi__reply-preview`,children:[(0,n.jsx)(`strong`,{children:e.replyTo.sender.name}),(0,n.jsx)(`span`,{children:e.replyTo.text??e.replyTo.attachments?.[0]?.name??`media`})]}):null,e.text?(0,n.jsx)(`p`,{children:e.text}):null,e.html?(0,n.jsx)(`div`,{className:`chatemi__message-html`,dangerouslySetInnerHTML:{__html:e.html}}):null,e.attachments?.length?(0,n.jsx)(`div`,{className:`chatemi__message-attachments`,children:e.attachments.map(e=>O(e,i))}):null,e.reactions?.length?(0,n.jsx)(`div`,{className:`chatemi__reactions`,children:e.reactions.map(e=>(0,n.jsxs)(`span`,{children:[e.emoji,` `,e.count]},e.emoji))}):null,(0,n.jsxs)(`footer`,{children:[(0,n.jsx)(`time`,{dateTime:e.createdAt,children:N(e.createdAt)}),t&&e.status?(0,n.jsx)(`span`,{children:F(e)}):null]}),r?(0,n.jsxs)(`div`,{className:`chatemi__message-actions`,children:[(0,n.jsx)(`button`,{onClick:()=>a(e),type:`button`,children:`Reply`}),(0,n.jsx)(`button`,{onClick:()=>o(e),type:`button`,children:`Forward`})]}):null]})}function O(e,t){return t&&e.type===`image`?(0,n.jsxs)(`a`,{className:`chatemi__media chatemi__media--image`,href:e.url,rel:`noreferrer`,target:`_blank`,children:[(0,n.jsx)(`img`,{alt:e.caption??e.name??`image`,src:e.url}),e.caption?(0,n.jsx)(`span`,{children:e.caption}):null]},e.id):t&&e.type===`video`?(0,n.jsxs)(`figure`,{className:`chatemi__media chatemi__media--video`,children:[(0,n.jsx)(`video`,{controls:!0,poster:e.thumbnailUrl,src:e.url}),(0,n.jsx)(`figcaption`,{children:e.caption??e.name??`Video`})]},e.id):e.type===`voice`||e.type===`audio`?(0,n.jsxs)(`div`,{className:`chatemi__media chatemi__media--audio`,children:[(0,n.jsx)(`span`,{children:e.type===`voice`?`Voice message`:e.name??`Audio`}),(0,n.jsx)(`audio`,{controls:!0,src:e.url})]},e.id):(0,n.jsxs)(`a`,{className:`chatemi__media chatemi__media--file`,href:e.url,rel:`noreferrer`,target:`_blank`,children:[e.thumbnailUrl?(0,n.jsx)(`img`,{alt:``,src:e.thumbnailUrl}):null,(0,n.jsx)(`span`,{children:e.name??e.type}),e.size?(0,n.jsx)(`small`,{children:z(e.size)}):null]},e.id)}function k({conversation:e,currentUserId:t}){let r=A(e,t),i=e.participants.find(e=>e.id!==t)??e.participants[0],a=e.avatarUrl??i?.avatarUrl;return a?(0,n.jsx)(`img`,{alt:``,className:`chatemi__avatar`,src:a}):(0,n.jsx)(`span`,{className:`chatemi__avatar chatemi__avatar--fallback`,children:r.slice(0,2).toUpperCase()})}function A(e,t){return e.title?e.title:e.participants.filter(e=>e.id!==t).map(e=>e.name).join(`, `)||`Untitled chat`}function j(e,t){if(e.type===`channel`)return`${e.participants.length} subscribers`;if(e.type===`group`)return`${e.participants.length} members`;let n=e.participants.find(e=>e.id!==t);return n?n.presence===`online`?`online`:n.lastSeenAt?`last seen ${P(n.lastSeenAt)}`:`last seen recently`:`Saved messages`}function M(e){switch(e){case`connected`:return`Realtime online`;case`connecting`:case`reconnecting`:return`Connecting`;case`error`:return`Connection issue`;default:return`Realtime idle`}}function N(e){return new Intl.DateTimeFormat(void 0,{hour:`2-digit`,minute:`2-digit`}).format(new Date(e))}function P(e){let t=Date.now()-Date.parse(e),n=Math.max(1,Math.round(t/6e4));if(n<60)return`${n}m ago`;let r=Math.round(n/60);return r<24?`${r}h ago`:`${Math.round(r/24)}d ago`}function F(e){return e.status===`read`||e.readBy?.length?`read`:e.status===`delivered`||e.deliveredTo?.length?`delivered`:e.status??`sent`}function I(e){return e.type.startsWith(`image/`)?`image`:e.type.startsWith(`video/`)?`video`:e.type.startsWith(`audio/`)?e.name.toLowerCase().includes(`voice`)?`voice`:`audio`:`file`}function L(e){return e.some(e=>e.type===`voice`)?`voice`:e.length>0?`media`:`text`}function R(e){return{user:e,role:`member`,joinedAt:new Date().toISOString()}}function z(e){return e<1024?`${e} B`:e<1024*1024?`${Math.round(e/1024)} KB`:`${(e/1024/1024).toFixed(1)} MB`}var B={width:420,height:680},V={width:340,height:480},H={width:920,height:860};function U({className:e,title:r=`Messages`,subtitle:i=`ChatEmi`,placement:a=`bottom-right`,defaultOpen:o=!1,showNotificationList:s=!0,badgeCount:c,initialSize:l=B,minSize:u=V,maxSize:d=H,markNotificationsReadOnOpen:f=!0,launcherIcon:p,...m}){let{actions:g,conversations:_,connectionStatus:v,notifications:y,theme:b,unreadNotificationCount:x}=h(),[S,C]=(0,t.useState)(o),[w,E]=(0,t.useState)({x:0,y:0}),D=(0,t.useRef)(void 0),O=(0,t.useMemo)(()=>_.reduce((e,t)=>e+(t.unreadCount??0),0),[_]),k=c??(x>0?x:O);function A(){C(e=>{let t=!e;return t&&f&&g.markNotificationsRead(),t&&g.requestNotificationPermission(),t})}function j(e){e.target.closest(`button`)||(e.currentTarget.setPointerCapture(e.pointerId),D.current={pointerId:e.pointerId,startX:e.clientX,startY:e.clientY,originX:w.x,originY:w.y})}function M(e){let t=D.current;!t||t.pointerId!==e.pointerId||E({x:t.originX+e.clientX-t.startX,y:t.originY+e.clientY-t.startY})}function N(e){D.current?.pointerId===e.pointerId&&(D.current=void 0)}return(0,n.jsxs)(`div`,{className:[`chatemi-launcher`,`chatemi-launcher--${a}`,e].filter(Boolean).join(` `),"data-theme":m.theme??b,children:[S?(0,n.jsxs)(`section`,{"aria-label":r,className:`chatemi-launcher__modal`,style:{width:l.width,height:l.height,minWidth:u.width,minHeight:u.height,maxWidth:d.width,maxHeight:d.height,transform:`translate(${w.x}px, ${w.y}px)`},children:[(0,n.jsxs)(`div`,{className:`chatemi-launcher__modal-header`,onPointerDown:j,onPointerMove:M,onPointerUp:N,onPointerCancel:N,children:[(0,n.jsxs)(`div`,{children:[(0,n.jsx)(`strong`,{children:r}),(0,n.jsxs)(`span`,{children:[i,` · `,v]})]}),(0,n.jsx)(`button`,{"aria-label":`Close messages`,onClick:A,type:`button`,children:`Close`})]}),s&&y.length>0?(0,n.jsxs)(`div`,{className:`chatemi-launcher__notifications`,"aria-label":`Notifications`,children:[y.slice(0,3).map(e=>(0,n.jsxs)(`button`,{className:e.read?`chatemi-launcher__notification`:`chatemi-launcher__notification chatemi-launcher__notification--unread`,onClick:()=>{e.conversationId&&g.openConversation(e.conversationId),g.markNotificationsRead([e.id])},type:`button`,children:[e.avatarUrl?(0,n.jsx)(`img`,{alt:``,src:e.avatarUrl}):(0,n.jsx)(`span`,{children:e.title.slice(0,2).toUpperCase()}),(0,n.jsxs)(`span`,{children:[(0,n.jsx)(`strong`,{children:e.title}),e.body?(0,n.jsx)(`small`,{children:e.body}):null]})]},e.id)),(0,n.jsx)(`button`,{className:`chatemi-launcher__clear`,onClick:g.clearNotifications,type:`button`,children:`Clear`})]}):null,(0,n.jsx)(T,{...m})]}):null,(0,n.jsxs)(`button`,{"aria-expanded":S,"aria-label":S?`Close messages`:`Open messages`,className:`chatemi-launcher__toggle`,onClick:A,type:`button`,children:[(0,n.jsx)(`span`,{className:`chatemi-launcher__icon`,children:p??(0,n.jsx)(W,{})}),k>0?(0,n.jsx)(`span`,{className:`chatemi-launcher__badge`,children:k>99?`99+`:k}):null]})]})}function W(){return(0,n.jsxs)(`svg`,{"aria-hidden":`true`,fill:`none`,height:`28`,viewBox:`0 0 28 28`,width:`28`,children:[(0,n.jsx)(`path`,{d:`M5 13.4C5 8.76 8.98 5 13.9 5h.2C19.02 5 23 8.76 23 13.4c0 4.62-3.98 8.38-8.9 8.38h-.64c-.42 0-.83.12-1.18.34l-3.54 2.2a.75.75 0 0 1-1.14-.64l.18-3.2a1.8 1.8 0 0 0-.5-1.36A8.06 8.06 0 0 1 5 13.4Z`,stroke:`currentColor`,strokeLinecap:`round`,strokeLinejoin:`round`,strokeWidth:`2`}),(0,n.jsx)(`path`,{d:`M10 12.5h8M10 16h5`,stroke:`currentColor`,strokeLinecap:`round`,strokeWidth:`2`})]})}e.ChatEmiApi=a,e.ChatEmiApiError=i,e.ChatEmiLauncher=U,e.ChatEmiMessenger=T,e.ChatEmiProvider=m,e.ChatEmiSocket=u,e.useChatEmi=h});
|
|
1
|
+
(function(e,t){typeof exports==`object`&&typeof module<`u`?t(exports,require("react"),require("react/jsx-runtime")):typeof define==`function`&&define.amd?define([`exports`,`react`,`react/jsx-runtime`],t):(e=typeof globalThis<`u`?globalThis:e||self,t(e.ChatEmi={},e.React,e.jsxRuntime))})(this,function(e,t,n){Object.defineProperty(e,Symbol.toStringTag,{value:`Module`});var r={me:`/me`,users:`/users`,user:e=>`/users/${encodeURIComponent(e)}`,conversations:`/conversations`,conversation:e=>`/conversations/${encodeURIComponent(e)}`,conversationAvatar:e=>`/conversations/${encodeURIComponent(e)}/avatar`,members:e=>`/conversations/${encodeURIComponent(e)}/members`,member:(e,t)=>`/conversations/${encodeURIComponent(e)}/members/${encodeURIComponent(t)}`,messages:e=>`/conversations/${encodeURIComponent(e)}/messages`,message:(e,t)=>`/conversations/${encodeURIComponent(e)}/messages/${encodeURIComponent(t)}`,markRead:e=>`/conversations/${encodeURIComponent(e)}/read`,markDelivered:e=>`/conversations/${encodeURIComponent(e)}/delivered`,forwardMessage:(e,t)=>`/conversations/${encodeURIComponent(e)}/messages/${encodeURIComponent(t)}/forward`,reactions:(e,t)=>`/conversations/${encodeURIComponent(e)}/messages/${encodeURIComponent(t)}/reactions`,upload:`/attachments`,search:`/search/messages`},i=class extends Error{status;payload;constructor(e,t,n){super(e),this.name=`ChatEmiApiError`,this.status=t,this.payload=n}},a=class{config;fetcher;constructor(e){this.config=e,this.fetcher=e.fetchImpl??((e,t)=>fetch(e,t))}async getMe(e){return this.request(this.endpoint(`me`),{signal:e})}async searchUsers(e,t){if(this.config.userDirectory){let n=this.config.userDirectory.searchPath??`/users`;return o(await this.request(n,{query:{q:e.query,cursor:e.cursor,limit:e.limit},signal:t,baseUrl:this.config.userDirectory.baseUrl,headers:await this.resolveUserDirectoryHeaders(),authorize:!1}),this.config.userDirectory.mapUser)}return this.request(this.endpoint(`users`),{query:{q:e.query,cursor:e.cursor,limit:e.limit},signal:t})}async getUser(e,t){if(this.config.userDirectory){let n=this.config.userDirectory.userPath?.(e)??`/users/${encodeURIComponent(e)}`,r=await this.request(n,{signal:t,baseUrl:this.config.userDirectory.baseUrl,headers:await this.resolveUserDirectoryHeaders(),authorize:!1});return this.config.userDirectory.mapUser?this.config.userDirectory.mapUser(r):r}return this.request(this.endpoint(`user`,e),{signal:t})}async listConversations(e={},t){return this.request(this.endpoint(`conversations`),{query:{...e},signal:t})}async getConversation(e,t){return this.request(this.endpoint(`conversation`,e),{signal:t})}async createConversation(e){return this.request(this.endpoint(`conversations`),{method:`POST`,body:e})}async createGroup(e){return this.createConversation({...e,type:`group`})}async createChannel(e){return this.createConversation({...e,type:`channel`,readOnly:e.readOnly??!0})}async updateConversation(e,t){return this.request(this.endpoint(`conversation`,e),{method:`PATCH`,body:t})}async archiveConversation(e){await this.request(this.endpoint(`conversation`,e),{method:`DELETE`})}async updateConversationAvatar(e){if(e.conversationId)return this.request(this.endpoint(`conversationAvatar`,e.conversationId),{method:`PATCH`,body:{attachment:e.attachment}});if(!e.userId)throw Error(`ChatEmi avatar update requires conversationId or userId`);return this.request(this.endpoint(`user`,e.userId),{method:`PATCH`,body:{avatar:e.attachment}})}async addMembers(e,t){return this.request(this.endpoint(`members`,e),{method:`POST`,body:{userIds:t}})}async updateMember(e){return this.request(this.endpoint(`member`,e.conversationId,e.userId),{method:`PATCH`,body:e})}async removeMember(e){await this.request(this.endpoint(`member`,e.conversationId,e.userId),{method:`DELETE`})}async listMessages(e,t={},n){return this.request(this.endpoint(`messages`,e),{query:{...t},signal:n})}async sendMessage(e){return this.request(this.endpoint(`messages`,e.conversationId),{method:`POST`,body:e})}async forwardMessage(e){return this.request(this.endpoint(`forwardMessage`,e.sourceConversationId,e.messageId),{method:`POST`,body:e})}async editMessage(e){return this.request(this.endpoint(`message`,e.conversationId,e.messageId),{method:`PATCH`,body:e})}async deleteMessage(e,t){await this.request(this.endpoint(`message`,e,t),{method:`DELETE`})}async markConversationRead(e,t){await this.request(this.endpoint(`markRead`,e),{method:`POST`,body:{messageIds:t}})}async markConversationDelivered(e,t){await this.request(this.endpoint(`markDelivered`,e),{method:`POST`,body:{messageIds:t}})}async addReaction(e,t,n){return this.request(this.endpoint(`reactions`,e,t),{method:`POST`,body:{emoji:n}})}async removeReaction(e,t,n){return this.request(this.endpoint(`reactions`,e,t),{method:`DELETE`,body:{emoji:n}})}async uploadAttachment(e){let t=new FormData;return t.append(`file`,e.file,e.name),e.conversationId&&t.append(`conversationId`,e.conversationId),e.type&&t.append(`type`,e.type),e.metadata&&t.append(`metadata`,JSON.stringify(e.metadata)),this.request(this.endpoint(`upload`),{method:`POST`,body:t})}async searchMessages(e,t={},n){return this.request(this.endpoint(`search`),{query:{q:e,...t},signal:n})}endpoint(e,t,n){switch(e){case`user`:case`conversation`:case`conversationAvatar`:case`members`:case`messages`:case`markRead`:case`markDelivered`:return(this.config.endpoints?.[e]??r[e])(t??``);case`member`:case`message`:case`forwardMessage`:case`reactions`:return(this.config.endpoints?.[e]??r[e])(t??``,n??``);default:return this.config.endpoints?.[e]??r[e]}}async request(e,t={}){let n=this.buildUrl(e,t.query,t.baseUrl),r=new Headers(await this.resolveHeaders(t.headers,t.authorize??!0)),a=typeof FormData<`u`&&t.body instanceof FormData;!a&&t.body!==void 0&&!r.has(`Content-Type`)&&r.set(`Content-Type`,`application/json`);let o=await this.fetcher(n,{method:t.method??`GET`,headers:r,body:a?t.body:t.body===void 0?void 0:JSON.stringify(t.body),signal:t.signal});if(o.status===204)return;let s=await this.parseResponse(o);if(!o.ok)throw new i(this.errorMessage(s,o.status),o.status,s);return s}buildUrl(e,t,n=this.config.apiBaseUrl){let r=/^https?:\/\//i.test(e),i=n.replace(/\/+$/,``),a=e.startsWith(`/`)?e:`/${e}`,o=new URL(r?e:`${i}${a}`);return Object.entries(t??{}).forEach(([e,t])=>{t!=null&&t!==``&&o.searchParams.set(e,String(t))}),o.toString()}async resolveHeaders(e,t=!0){let n=new Headers,r=typeof this.config.headers==`function`?await this.config.headers():this.config.headers,i=typeof this.config.token==`function`?await this.config.token():this.config.token;return new Headers(r).forEach((e,t)=>n.set(t,e)),new Headers(e).forEach((e,t)=>n.set(t,e)),t&&i&&!n.has(`Authorization`)&&n.set(`Authorization`,`Bearer ${i}`),n}async resolveUserDirectoryHeaders(){return(typeof this.config.userDirectory?.headers==`function`?await this.config.userDirectory.headers():this.config.userDirectory?.headers)??{}}async parseResponse(e){return(e.headers.get(`Content-Type`)??``).includes(`application/json`)?e.json():e.text()}errorMessage(e,t){return e&&typeof e==`object`&&`message`in e&&typeof e.message==`string`?e.message:`ChatEmi API request failed with status ${t}`}};function o(e,t){let n=e=>t?t(e):e;return Array.isArray(e)?{items:e.map(n)}:{...e,items:e.items.map(n)}}var s=500,c=8e3,l=1/0,u=class{config;socket;reconnectAttempts=0;shouldReconnect=!0;reconnectTimer;queue=[];listeners=new Map;constructor(e){this.config=e}get readyState(){return this.socket?.readyState}async connect(){this.config.socketUrl&&(this.socket?.readyState===WebSocket.OPEN||this.socket?.readyState===WebSocket.CONNECTING||(this.shouldReconnect=this.config.reconnect?.enabled??!0,this.createSocket(await this.buildSocketUrl())))}disconnect(){this.shouldReconnect=!1,this.clearReconnectTimer(),this.socket?.close(),this.socket=void 0}on(e,t){let n=this.listeners.get(e)??new Set;return n.add(t),this.listeners.set(e,n),()=>{n.delete(t),n.size===0&&this.listeners.delete(e)}}send(e,t,n){let r={type:e,payload:t,requestId:n};if(this.socket?.readyState===WebSocket.OPEN){this.socket.send(JSON.stringify(r));return}this.queue.push(r)}subscribeConversation(e){this.send(`conversation.subscribe`,{conversationId:e})}unsubscribeConversation(e){this.send(`conversation.unsubscribe`,{conversationId:e})}sendTyping(e,t){this.send(`typing`,{conversationId:e,isTyping:t})}sendReadReceipt(e,t){this.send(`message.read`,{conversationId:e,messageIds:t})}sendDeliveredReceipt(e,t){this.send(`message.delivered`,{conversationId:e,messageIds:t})}sendForward(e){this.send(`message.forward`,e)}sendMemberUpdate(e){this.send(`conversation.member.update`,e)}sendAvatarUpdate(e){this.send(`conversation.avatar.update`,{conversationId:e})}sendPresence(e){this.send(`presence`,{status:e})}createSocket(e){let t=(this.config.websocketFactory??(e=>new WebSocket(e)))(e);this.socket=t,t.addEventListener(`open`,()=>{this.reconnectAttempts=0,this.dispatch(`connected`,void 0),this.flushQueue()}),t.addEventListener(`close`,e=>{this.dispatch(`disconnected`,e),this.socket=void 0,this.scheduleReconnect()}),t.addEventListener(`error`,e=>{this.dispatch(`error`,e)}),t.addEventListener(`message`,e=>{this.handleMessage(e.data)})}handleMessage(e){try{let t=typeof e==`string`?JSON.parse(e):e;t&&typeof t.type==`string`&&this.dispatchRaw(t.type,t.payload)}catch(e){this.dispatch(`error`,e instanceof Error?e:Error(`Unable to parse ChatEmi socket message`))}}flushQueue(){for(;this.queue.length>0&&this.socket?.readyState===WebSocket.OPEN;){let e=this.queue.shift();e&&this.socket.send(JSON.stringify(e))}}scheduleReconnect(){if(!this.shouldReconnect||!this.config.socketUrl)return;let e=this.config.reconnect?.maxAttempts??l;if(this.reconnectAttempts>=e)return;this.reconnectAttempts+=1;let t=this.config.reconnect?.initialDelayMs??s,n=this.config.reconnect?.maxDelayMs??c,r=Math.min(t*2**(this.reconnectAttempts-1),n);this.dispatch(`reconnecting`,{attempt:this.reconnectAttempts,delay:r}),this.clearReconnectTimer(),this.reconnectTimer=setTimeout(()=>{this.connect()},r)}async buildSocketUrl(){let e=this.config.socketUrl;if(!e)throw Error(`ChatEmi socketUrl is required before connecting the socket`);let t=new URL(e),n=typeof this.config.token==`function`?await this.config.token():this.config.token;return n&&t.searchParams.set(`token`,n),t.toString()}dispatch(e,t){this.listeners.get(e)?.forEach(e=>e(t))}dispatchRaw(e,t){this.listeners.get(e)?.forEach(e=>e(t))}clearReconnectTimer(){this.reconnectTimer&&=(clearTimeout(this.reconnectTimer),void 0)}},d=(0,t.createContext)(void 0);function f(e,t=[],n,r=[]){return{currentUser:e.currentUser,conversations:t,activeConversationId:n??t[0]?.id,messagesByConversation:{},typingByConversation:{},presenceByUser:{},notifications:r,unreadNotificationCount:r.filter(e=>!e.read).length,connectionStatus:`idle`,theme:e.theme??`light`,loading:!1}}function p(e,t){switch(t.type){case`set-loading`:return{...e,loading:t.loading};case`set-error`:return{...e,error:t.error};case`set-connection-status`:return{...e,connectionStatus:t.status};case`set-current-user`:return{...e,currentUser:t.user};case`set-conversations`:return{...e,conversations:b(t.conversations),activeConversationId:e.activeConversationId??t.conversations[0]?.id};case`upsert-conversation`:return{...e,conversations:b(g(e.conversations,t.conversation))};case`remove-conversation`:return{...e,conversations:e.conversations.filter(e=>e.id!==t.conversationId),activeConversationId:e.activeConversationId===t.conversationId?void 0:e.activeConversationId};case`upsert-member`:return{...e,conversations:e.conversations.map(e=>e.id===t.conversationId?{...e,members:_(e.members??[],t.member),participants:g(e.participants,t.member.user)}:e)};case`remove-member`:return{...e,conversations:e.conversations.map(e=>e.id===t.conversationId?{...e,members:(e.members??[]).filter(e=>e.user.id!==t.userId),participants:e.participants.filter(e=>e.id!==t.userId)}:e)};case`set-active-conversation`:return{...e,activeConversationId:t.conversationId};case`set-messages`:return{...e,messagesByConversation:{...e.messagesByConversation,[t.conversationId]:x(t.messages)}};case`upsert-message`:{let n=e.messagesByConversation[t.message.conversationId]??[],r=S(e.conversations,t.message);return{...e,conversations:r,messagesByConversation:{...e.messagesByConversation,[t.message.conversationId]:x(g(n,t.message))}}}case`remove-message`:return{...e,messagesByConversation:{...e.messagesByConversation,[t.conversationId]:(e.messagesByConversation[t.conversationId]??[]).filter(e=>e.id!==t.messageId)}};case`set-message-reactions`:return{...e,messagesByConversation:{...e.messagesByConversation,[t.conversationId]:(e.messagesByConversation[t.conversationId]??[]).map(e=>e.id===t.messageId?{...e,reactions:t.reactions}:e)}};case`apply-receipt`:return{...e,messagesByConversation:{...e.messagesByConversation,[t.receipt.conversationId]:(e.messagesByConversation[t.receipt.conversationId]??[]).map(e=>t.receipt.messageIds.includes(e.id)?v(e,t.receipt):e)}};case`add-notification`:{let n=(e.notifications.some(e=>e.id===t.notification.id)?e.notifications.map(e=>e.id===t.notification.id?t.notification:e):[t.notification,...e.notifications]).slice(0,t.maxStored??50);return{...e,notifications:n,unreadNotificationCount:n.filter(e=>!e.read).length}}case`dismiss-notification`:{let n=e.notifications.filter(e=>e.id!==t.notificationId);return{...e,notifications:n,unreadNotificationCount:n.filter(e=>!e.read).length}}case`mark-notifications-read`:{let n=t.notificationIds?new Set(t.notificationIds):void 0,r=e.notifications.map(e=>!n||n.has(e.id)?{...e,read:!0}:e);return{...e,notifications:r,unreadNotificationCount:r.filter(e=>!e.read).length}}case`clear-notifications`:return{...e,notifications:[],unreadNotificationCount:0};case`set-typing`:{let n=(e.typingByConversation[t.event.conversationId]??[]).filter(e=>e.user.id!==t.event.user.id);return{...e,typingByConversation:{...e.typingByConversation,[t.event.conversationId]:t.event.isTyping?[...n,t.event]:n}}}case`set-presence`:return{...e,presenceByUser:{...e.presenceByUser,[t.userId]:{userId:t.userId,status:t.status,lastSeenAt:t.lastSeenAt}}};default:return e}}function m({children:e,config:r,autoConnect:i=!0,initialConversations:o,initialActiveConversationId:s,initialNotifications:c}){let l=(0,t.useMemo)(()=>new a(r),[r]),m=(0,t.useMemo)(()=>new u(r),[r]),h=(0,t.useRef)({activeConversationId:s,currentUserId:r.currentUser?.id}),g=(0,t.useRef)(new Set),[_,v]=(0,t.useReducer)(p,f(r,o,s,c));(0,t.useEffect)(()=>{h.current={activeConversationId:_.activeConversationId,currentUserId:_.currentUser?.id}},[_.activeConversationId,_.currentUser?.id]),(0,t.useEffect)(()=>{let e=!0,t=new AbortController;v({type:`set-current-user`,user:r.currentUser});async function n(){v({type:`set-loading`,loading:!0}),v({type:`set-error`,error:void 0});try{let[n,i]=await Promise.all([r.currentUser?Promise.resolve(r.currentUser):l.getMe(t.signal).catch(()=>void 0),l.listConversations({},t.signal)]);if(!e)return;v({type:`set-current-user`,user:n}),v({type:`set-conversations`,conversations:i.items})}catch(t){e&&v({type:`set-error`,error:w(t)})}finally{e&&v({type:`set-loading`,loading:!1})}}return n(),()=>{e=!1,t.abort()}},[l,r.currentUser]),(0,t.useEffect)(()=>{let e=[m.on(`connected`,()=>v({type:`set-connection-status`,status:`connected`})),m.on(`disconnected`,()=>v({type:`set-connection-status`,status:`disconnected`})),m.on(`reconnecting`,()=>v({type:`set-connection-status`,status:`reconnecting`})),m.on(`error`,e=>{v({type:`set-connection-status`,status:`error`}),v({type:`set-error`,error:w(e)})}),m.on(`conversation.created`,e=>v({type:`upsert-conversation`,conversation:e})),m.on(`conversation.updated`,e=>v({type:`upsert-conversation`,conversation:e})),m.on(`conversation.deleted`,({conversationId:e})=>v({type:`remove-conversation`,conversationId:e})),m.on(`conversation.member.added`,({conversationId:e,member:t})=>v({type:`upsert-member`,conversationId:e,member:t})),m.on(`conversation.member.updated`,({conversationId:e,member:t})=>v({type:`upsert-member`,conversationId:e,member:t})),m.on(`conversation.member.removed`,({conversationId:e,userId:t})=>v({type:`remove-member`,conversationId:e,userId:t})),m.on(`message.created`,e=>{v({type:`upsert-message`,message:e}),e.sender.id!==h.current.currentUserId&&v({type:`add-notification`,notification:C(e),maxStored:r.notifications?.maxStored})}),m.on(`message.updated`,e=>v({type:`upsert-message`,message:e})),m.on(`message.deleted`,({conversationId:e,messageId:t})=>v({type:`remove-message`,conversationId:e,messageId:t})),m.on(`message.receipt`,e=>v({type:`apply-receipt`,receipt:e})),m.on(`message.reaction`,({conversationId:e,messageId:t,reactions:n})=>v({type:`set-message-reactions`,conversationId:e,messageId:t,reactions:n})),m.on(`typing`,e=>v({type:`set-typing`,event:e})),m.on(`presence`,({userId:e,status:t,lastSeenAt:n})=>v({type:`set-presence`,userId:e,status:t,lastSeenAt:n})),m.on(`notification`,e=>v({type:`add-notification`,notification:e,maxStored:r.notifications?.maxStored}))];return i&&r.socketUrl&&(v({type:`set-connection-status`,status:`connecting`}),m.connect()),()=>{e.forEach(e=>e()),m.disconnect()}},[i,r.notifications?.maxStored,r.socketUrl,m]),(0,t.useEffect)(()=>{!r.notifications?.enabled||!r.notifications.browser||typeof window>`u`||!(`Notification`in window)||window.Notification.permission!==`granted`||(r.notifications.showWhenOpen||typeof document>`u`||document.hidden)&&_.notifications.forEach(e=>{e.read||g.current.has(e.id)||(g.current.add(e.id),new window.Notification(e.title||r.notifications?.title||`New message`,{body:e.body,icon:e.avatarUrl}))})},[r.notifications,_.notifications]);let y=(0,t.useCallback)(async(e={})=>{v({type:`set-loading`,loading:!0});try{let t=await l.listConversations(e);return v({type:`set-conversations`,conversations:t.items}),t.items}finally{v({type:`set-loading`,loading:!1})}},[l]),b=(0,t.useCallback)(async(e,t={})=>{v({type:`set-active-conversation`,conversationId:e}),m.subscribeConversation(e);let n=await l.listMessages(e,t);return v({type:`set-messages`,conversationId:e,messages:n.items}),l.markConversationDelivered(e,n.items.filter(e=>e.sender.id!==_.currentUser?.id).map(e=>e.id)),n.items},[l,m,_.currentUser?.id]),x=(0,t.useCallback)(async e=>{let t=await l.createConversation(e);return v({type:`upsert-conversation`,conversation:t}),v({type:`set-active-conversation`,conversationId:t.id}),t},[l]),S=(0,t.useCallback)(async e=>{let t=`temp-${Date.now()}`,n=_.currentUser?{id:t,conversationId:e.conversationId,sender:_.currentUser,text:e.text,html:e.html,attachments:e.attachments,kind:e.kind,replyToId:e.replyToId,status:`sending`,createdAt:new Date().toISOString(),metadata:e.metadata}:void 0;n&&v({type:`upsert-message`,message:n});try{let r=await l.sendMessage(e);return n&&v({type:`remove-message`,conversationId:e.conversationId,messageId:t}),v({type:`upsert-message`,message:r}),r}catch(e){throw n&&v({type:`upsert-message`,message:{...n,status:`failed`}}),e}},[l,_.currentUser]),T=(0,t.useCallback)(async e=>{let t=await l.editMessage(e);return v({type:`upsert-message`,message:t}),t},[l]),E=(0,t.useCallback)(async(e,t)=>{await l.deleteMessage(e,t),v({type:`remove-message`,conversationId:e,messageId:t})},[l]),D=(0,t.useCallback)(async(e,t)=>{await l.markConversationRead(e,t),m.sendReadReceipt(e,t??[])},[l,m]),O=(0,t.useCallback)(async(e,t)=>{await l.markConversationDelivered(e,t),m.sendDeliveredReceipt(e,t??[])},[l,m]),k=(0,t.useCallback)(async e=>{let t=await l.forwardMessage(e);return m.sendForward(e),v({type:`upsert-message`,message:t}),t},[l,m]),A=(0,t.useCallback)(async(e,t,n)=>{let r=await l.addReaction(e,t,n);return v({type:`upsert-message`,message:r}),r},[l]),j=(0,t.useCallback)(async(e,t,n)=>{let r=await l.removeReaction(e,t,n);return v({type:`upsert-message`,message:r}),r},[l]),M=(0,t.useCallback)(e=>l.uploadAttachment(e),[l]),N=(0,t.useCallback)(async e=>{let t=await l.updateConversationAvatar(e);return`participants`in t?(v({type:`upsert-conversation`,conversation:t}),m.sendAvatarUpdate(t.id)):v({type:`set-current-user`,user:_.currentUser?.id===t.id?t:_.currentUser}),t},[l,m,_.currentUser]),P=(0,t.useCallback)(async(e,t)=>{let n=await l.addMembers(e,t);return n.forEach(t=>v({type:`upsert-member`,conversationId:e,member:t})),n},[l]),F=(0,t.useCallback)(async e=>{let t=await l.updateMember(e);return v({type:`upsert-member`,conversationId:e.conversationId,member:t}),m.sendMemberUpdate(e),t},[l,m]),I=(0,t.useCallback)(async e=>{await l.removeMember(e),v({type:`remove-member`,conversationId:e.conversationId,userId:e.userId})},[l]),L=(0,t.useCallback)(async e=>(await l.searchUsers(e)).items,[l]),R=(0,t.useCallback)(async(e,t={})=>(await l.searchMessages(e,t)).items,[l]),z=(0,t.useCallback)(e=>m.sendTyping(e,!0),[m]),B=(0,t.useCallback)(e=>m.sendTyping(e,!1),[m]),V=(0,t.useCallback)(e=>m.sendPresence(e),[m]),H=(0,t.useCallback)(e=>{v({type:`dismiss-notification`,notificationId:e})},[]),U=(0,t.useCallback)(e=>{v({type:`mark-notifications-read`,notificationIds:e})},[]),W=(0,t.useCallback)(()=>{v({type:`clear-notifications`})},[]),G=(0,t.useCallback)(async()=>typeof window>`u`||!(`Notification`in window)?`unsupported`:window.Notification.permission===`granted`||window.Notification.permission===`denied`?window.Notification.permission:window.Notification.requestPermission(),[]),K=(0,t.useCallback)(()=>m.connect(),[m]),q=(0,t.useCallback)(()=>m.disconnect(),[m]),J=(0,t.useMemo)(()=>({refreshConversations:y,openConversation:b,createConversation:x,sendMessage:S,editMessage:T,deleteMessage:E,markRead:D,markDelivered:O,forwardMessage:k,addReaction:A,removeReaction:j,uploadAttachment:M,updateAvatar:N,addMembers:P,updateMember:F,removeMember:I,searchUsers:L,searchMessages:R,startTyping:z,stopTyping:B,setPresence:V,dismissNotification:H,markNotificationsRead:U,clearNotifications:W,requestNotificationPermission:G,connect:K,disconnect:q}),[y,b,x,S,T,E,D,O,k,A,j,M,N,P,F,I,L,R,z,B,V,H,U,W,G,K,q]),Y=_.conversations.find(e=>e.id===_.activeConversationId),X=_.activeConversationId?_.messagesByConversation[_.activeConversationId]??[]:[],Z=(0,t.useMemo)(()=>({..._,api:l,socket:m,activeConversation:Y,activeMessages:X,actions:J}),[J,Y,X,l,m,_]);return(0,n.jsx)(d.Provider,{value:Z,children:e})}function h(){let e=(0,t.useContext)(d);if(!e)throw Error(`useChatEmi must be used inside a ChatEmiProvider`);return e}function g(e,t){let n=e.findIndex(e=>e.id===t.id);return n===-1?[...e,t]:[...e.slice(0,n),t,...e.slice(n+1)]}function _(e,t){let n=e.findIndex(e=>e.user.id===t.user.id);return n===-1?[...e,t]:[...e.slice(0,n),t,...e.slice(n+1)]}function v(e,t){let n=t.status===`read`?`readBy`:`deliveredTo`,r=y(e[n]??[],t);return{...e,[n]:r,status:t.status===`read`||e.status===`read`?`read`:`delivered`}}function y(e,t){let n=e.findIndex(e=>e.userId===t.userId&&e.status===t.status);return n===-1?[...e,t]:[...e.slice(0,n),t,...e.slice(n+1)]}function b(e){return[...e].sort((e,t)=>{let n=e.lastMessage?.createdAt??e.updatedAt??e.createdAt,r=t.lastMessage?.createdAt??t.updatedAt??t.createdAt;return Date.parse(r)-Date.parse(n)})}function x(e){return[...e].sort((e,t)=>Date.parse(e.createdAt)-Date.parse(t.createdAt))}function S(e,t){return b(e.map(e=>e.id===t.conversationId?{...e,lastMessage:t,updatedAt:t.createdAt}:e))}function C(e){return{id:`message:${e.id}`,kind:`message`,title:e.sender.name,body:e.text??e.attachments?.[0]?.name??`Sent a message`,conversationId:e.conversationId,messageId:e.id,actor:e.sender,avatarUrl:e.sender.avatarUrl,read:!1,createdAt:e.createdAt,metadata:e.metadata}}function w(e){return e instanceof Error?e.message:`Unexpected ChatEmi error`}function T({className:e,emptyState:r,composerPlaceholder:i=`Write a message...`,showSidebar:a=!0,theme:o,enableAdminControls:s=!0,enableMessageActions:c=!0,enableMediaPreview:l=!0,renderConversation:u,renderMessage:d}){let{actions:f,activeConversation:p,activeMessages:m,connectionStatus:g,conversations:_,currentUser:v,error:y,loading:b,theme:x,typingByConversation:S}=h(),[C,w]=(0,t.useState)(``),[T,O]=(0,t.useState)(``),[N,P]=(0,t.useState)(``),[F,z]=(0,t.useState)([]),[B,V]=(0,t.useState)(!1),[H,U]=(0,t.useState)(),[W,G]=(0,t.useState)([]),[K,q]=(0,t.useState)(!1),J=(0,t.useRef)(void 0),Y=o??x,X=(0,t.useMemo)(()=>{let e=T.trim().toLowerCase();return e?_.filter(t=>A(t,v?.id).toLowerCase().includes(e)):_},[_,v?.id,T]),Z=p?S[p.id]??[]:[],Q=(0,t.useMemo)(()=>m.map(e=>e.id).join(`,`),[m]),$=p?.members?.find(e=>e.user.id===v?.id),ee=s&&!!($&&[`owner`,`admin`,`moderator`].includes($.role));(0,t.useEffect)(()=>{if(!p||!Q)return;let e=m.filter(e=>e.sender.id!==v?.id).map(e=>e.id);e.length>0&&f.markRead(p.id,e)},[f,p,m,v?.id,Q]),(0,t.useEffect)(()=>{let e=!0;async function t(){if(N.trim().length<2){z([]);return}let t=await f.searchUsers({query:N.trim(),limit:8});e&&z(t)}return t(),()=>{e=!1}},[f,N]);async function te(e){if(e.preventDefault(),!p||!C.trim()&&W.length===0)return;let t=C.trim(),n=W;w(``),G([]),f.stopTyping(p.id);try{await f.sendMessage({conversationId:p.id,text:t||void 0,attachments:n.length>0?n:void 0,kind:L(n),replyToId:H?.id}),U(void 0)}catch{w(t),G(n)}}async function ne(e){if(e?.length){q(!0);try{let t=await Promise.all(Array.from(e).map(e=>f.uploadAttachment({file:e,name:e.name,type:I(e)})));G(e=>[...e,...t])}finally{q(!1)}}}function re(e){w(e),p&&(f.startTyping(p.id),J.current&&clearTimeout(J.current),J.current=setTimeout(()=>f.stopTyping(p.id),1400))}return(0,n.jsxs)(`section`,{className:[`chatemi`,e].filter(Boolean).join(` `),"data-status":g,"data-theme":Y,children:[a?(0,n.jsxs)(`aside`,{className:`chatemi__sidebar`,"aria-label":`Conversations`,children:[(0,n.jsxs)(`div`,{className:`chatemi__brand`,children:[(0,n.jsxs)(`div`,{children:[(0,n.jsx)(`strong`,{children:`ChatEmi`}),(0,n.jsx)(`span`,{children:M(g)})]}),(0,n.jsx)(`span`,{className:`chatemi__status chatemi__status--${g}`})]}),(0,n.jsxs)(`label`,{className:`chatemi__search`,children:[(0,n.jsx)(`span`,{className:`chatemi__sr-only`,children:`Search conversations`}),(0,n.jsx)(`input`,{value:T,onChange:e=>O(e.target.value),placeholder:`Search chats`})]}),(0,n.jsx)(`div`,{className:`chatemi__conversation-list`,children:X.map(e=>{let t=e.id===p?.id;return(0,n.jsx)(`button`,{className:`chatemi__conversation ${t?`chatemi__conversation--active`:``}`,onClick:()=>void f.openConversation(e.id),type:`button`,children:u?u(e,t):(0,n.jsx)(E,{conversation:e,currentUserId:v?.id})},e.id)})})]}):null,(0,n.jsxs)(`main`,{className:`chatemi__main`,children:[p?(0,n.jsxs)(n.Fragment,{children:[(0,n.jsxs)(`header`,{className:`chatemi__header`,children:[(0,n.jsx)(k,{conversation:p,currentUserId:v?.id}),(0,n.jsxs)(`div`,{children:[(0,n.jsx)(`strong`,{children:A(p,v?.id)}),(0,n.jsx)(`span`,{children:Z.length>0?`${Z.map(e=>e.user.name).join(`, `)} typing...`:j(p,v?.id)})]}),ee?(0,n.jsx)(`button`,{className:`chatemi__header-action`,onClick:()=>V(e=>!e),type:`button`,children:`Members`}):null]}),B&&p?(0,n.jsxs)(`section`,{className:`chatemi__members`,"aria-label":`Member management`,children:[(0,n.jsx)(`div`,{className:`chatemi__members-list`,children:(p.members??p.participants.map(e=>R(e))).map(e=>(0,n.jsxs)(`div`,{className:`chatemi__member`,children:[e.user.avatarUrl?(0,n.jsx)(`img`,{alt:``,className:`chatemi__member-avatar`,src:e.user.avatarUrl}):(0,n.jsx)(`span`,{className:`chatemi__member-avatar`,children:e.user.name.slice(0,2).toUpperCase()}),(0,n.jsxs)(`span`,{children:[(0,n.jsx)(`strong`,{children:e.user.name}),(0,n.jsx)(`small`,{children:e.role})]}),e.role!==`owner`&&e.user.id!==v?.id?(0,n.jsxs)(`span`,{className:`chatemi__member-actions`,children:[(0,n.jsx)(`button`,{onClick:()=>void f.updateMember({conversationId:p.id,userId:e.user.id,role:`admin`}),type:`button`,children:`Admin`}),(0,n.jsx)(`button`,{onClick:()=>void f.updateMember({conversationId:p.id,userId:e.user.id,role:`member`}),type:`button`,children:`Member`}),(0,n.jsx)(`button`,{onClick:()=>void f.removeMember({conversationId:p.id,userId:e.user.id}),type:`button`,children:`Remove`})]}):null]},e.user.id))}),(0,n.jsxs)(`label`,{className:`chatemi__member-search`,children:[(0,n.jsx)(`span`,{children:`Find users from external directory`}),(0,n.jsx)(`input`,{onChange:e=>P(e.target.value),placeholder:`Search users`,value:N})]}),F.length>0?(0,n.jsx)(`div`,{className:`chatemi__user-results`,children:F.map(e=>(0,n.jsxs)(`button`,{onClick:()=>void f.addMembers(p.id,[e.id]),type:`button`,children:[e.avatarUrl?(0,n.jsx)(`img`,{alt:``,src:e.avatarUrl}):null,`Add `,e.name]},e.id))}):null]}):null,(0,n.jsxs)(`div`,{className:`chatemi__messages`,role:`log`,"aria-live":`polite`,children:[m.map(e=>{let t=e.sender.id===v?.id;return d?(0,n.jsx)(`div`,{className:`chatemi__message-shell`,children:d(e,t)},e.id):(0,n.jsx)(D,{enableActions:c,enableMediaPreview:l,isMine:t,message:e,onForward:e=>{let t=window.prompt(`Forward to conversation id`);t&&f.forwardMessage({sourceConversationId:e.conversationId,targetConversationId:t,messageId:e.id})},onReply:U},e.id)}),m.length===0&&!b?(0,n.jsx)(`div`,{className:`chatemi__empty`,children:`No messages yet. Start the conversation.`}):null]}),W.length>0?(0,n.jsx)(`div`,{className:`chatemi__attachments`,children:W.map(e=>(0,n.jsx)(`button`,{className:`chatemi__attachment-pill`,onClick:()=>G(t=>t.filter(t=>t.id!==e.id)),type:`button`,children:e.name??e.type},e.id))}):null,H?(0,n.jsxs)(`div`,{className:`chatemi__replying`,children:[(0,n.jsxs)(`span`,{children:[`Replying to `,(0,n.jsx)(`strong`,{children:H.sender.name}),`: `,H.text??H.attachments?.[0]?.name??`media`]}),(0,n.jsx)(`button`,{onClick:()=>U(void 0),type:`button`,children:`Cancel`})]}):null,(0,n.jsxs)(`form`,{className:`chatemi__composer`,onSubmit:e=>void te(e),children:[(0,n.jsxs)(`label`,{className:`chatemi__upload`,children:[(0,n.jsx)(`span`,{children:K?`Uploading`:`Attach`}),(0,n.jsx)(`input`,{disabled:K,multiple:!0,onChange:e=>void ne(e.target.files),type:`file`})]}),(0,n.jsx)(`textarea`,{onBlur:()=>f.stopTyping(p.id),onChange:e=>re(e.target.value),placeholder:i,rows:1,value:C}),(0,n.jsx)(`button`,{disabled:K||!C.trim()&&W.length===0,type:`submit`,children:`Send`})]})]}):r??(0,n.jsx)(`div`,{className:`chatemi__empty chatemi__empty--screen`,children:`Select a conversation to start messaging.`}),y?(0,n.jsx)(`div`,{className:`chatemi__error`,children:y}):null]})]})}function E({conversation:e,currentUserId:t}){return(0,n.jsxs)(n.Fragment,{children:[(0,n.jsx)(k,{conversation:e,currentUserId:t}),(0,n.jsxs)(`span`,{className:`chatemi__conversation-body`,children:[(0,n.jsx)(`strong`,{children:A(e,t)}),(0,n.jsx)(`small`,{children:e.lastMessage?.text??e.description??`No messages yet`})]}),e.unreadCount?(0,n.jsx)(`span`,{className:`chatemi__badge`,children:e.unreadCount}):null]})}function D({message:e,isMine:t,enableActions:r,enableMediaPreview:i,onReply:a,onForward:o}){return(0,n.jsxs)(`article`,{className:`chatemi__message ${t?`chatemi__message--mine`:``}`,children:[t?null:(0,n.jsx)(`strong`,{className:`chatemi__message-sender`,children:e.sender.name}),e.forwardedFrom?(0,n.jsxs)(`div`,{className:`chatemi__forwarded`,children:[`Forwarded from `,e.forwardedFrom.name]}):null,e.replyTo?(0,n.jsxs)(`blockquote`,{className:`chatemi__reply-preview`,children:[(0,n.jsx)(`strong`,{children:e.replyTo.sender.name}),(0,n.jsx)(`span`,{children:e.replyTo.text??e.replyTo.attachments?.[0]?.name??`media`})]}):null,e.text?(0,n.jsx)(`p`,{children:e.text}):null,e.html?(0,n.jsx)(`div`,{className:`chatemi__message-html`,dangerouslySetInnerHTML:{__html:e.html}}):null,e.attachments?.length?(0,n.jsx)(`div`,{className:`chatemi__message-attachments`,children:e.attachments.map(e=>O(e,i))}):null,e.reactions?.length?(0,n.jsx)(`div`,{className:`chatemi__reactions`,children:e.reactions.map(e=>(0,n.jsxs)(`span`,{children:[e.emoji,` `,e.count]},e.emoji))}):null,(0,n.jsxs)(`footer`,{children:[(0,n.jsx)(`time`,{dateTime:e.createdAt,children:N(e.createdAt)}),t&&e.status?(0,n.jsx)(`span`,{children:F(e)}):null]}),r?(0,n.jsxs)(`div`,{className:`chatemi__message-actions`,children:[(0,n.jsx)(`button`,{onClick:()=>a(e),type:`button`,children:`Reply`}),(0,n.jsx)(`button`,{onClick:()=>o(e),type:`button`,children:`Forward`})]}):null]})}function O(e,t){return t&&e.type===`image`?(0,n.jsxs)(`a`,{className:`chatemi__media chatemi__media--image`,href:e.url,rel:`noreferrer`,target:`_blank`,children:[(0,n.jsx)(`img`,{alt:e.caption??e.name??`image`,src:e.url}),e.caption?(0,n.jsx)(`span`,{children:e.caption}):null]},e.id):t&&e.type===`video`?(0,n.jsxs)(`figure`,{className:`chatemi__media chatemi__media--video`,children:[(0,n.jsx)(`video`,{controls:!0,poster:e.thumbnailUrl,src:e.url}),(0,n.jsx)(`figcaption`,{children:e.caption??e.name??`Video`})]},e.id):e.type===`voice`||e.type===`audio`?(0,n.jsxs)(`div`,{className:`chatemi__media chatemi__media--audio`,children:[(0,n.jsx)(`span`,{children:e.type===`voice`?`Voice message`:e.name??`Audio`}),(0,n.jsx)(`audio`,{controls:!0,src:e.url})]},e.id):(0,n.jsxs)(`a`,{className:`chatemi__media chatemi__media--file`,href:e.url,rel:`noreferrer`,target:`_blank`,children:[e.thumbnailUrl?(0,n.jsx)(`img`,{alt:``,src:e.thumbnailUrl}):null,(0,n.jsx)(`span`,{children:e.name??e.type}),e.size?(0,n.jsx)(`small`,{children:z(e.size)}):null]},e.id)}function k({conversation:e,currentUserId:t}){let r=A(e,t),i=e.participants.find(e=>e.id!==t)??e.participants[0],a=e.avatarUrl??i?.avatarUrl;return a?(0,n.jsx)(`img`,{alt:``,className:`chatemi__avatar`,src:a}):(0,n.jsx)(`span`,{className:`chatemi__avatar chatemi__avatar--fallback`,children:r.slice(0,2).toUpperCase()})}function A(e,t){return e.title?e.title:e.participants.filter(e=>e.id!==t).map(e=>e.name).join(`, `)||`Untitled chat`}function j(e,t){if(e.type===`channel`)return`${e.participants.length} subscribers`;if(e.type===`group`)return`${e.participants.length} members`;let n=e.participants.find(e=>e.id!==t);return n?n.presence===`online`?`online`:n.lastSeenAt?`last seen ${P(n.lastSeenAt)}`:`last seen recently`:`Saved messages`}function M(e){switch(e){case`connected`:return`Realtime online`;case`connecting`:case`reconnecting`:return`Connecting`;case`error`:return`Connection issue`;default:return`Realtime idle`}}function N(e){return new Intl.DateTimeFormat(void 0,{hour:`2-digit`,minute:`2-digit`}).format(new Date(e))}function P(e){let t=Date.now()-Date.parse(e),n=Math.max(1,Math.round(t/6e4));if(n<60)return`${n}m ago`;let r=Math.round(n/60);return r<24?`${r}h ago`:`${Math.round(r/24)}d ago`}function F(e){return e.status===`read`||e.readBy?.length?`read`:e.status===`delivered`||e.deliveredTo?.length?`delivered`:e.status??`sent`}function I(e){return e.type.startsWith(`image/`)?`image`:e.type.startsWith(`video/`)?`video`:e.type.startsWith(`audio/`)?e.name.toLowerCase().includes(`voice`)?`voice`:`audio`:`file`}function L(e){return e.some(e=>e.type===`voice`)?`voice`:e.length>0?`media`:`text`}function R(e){return{user:e,role:`member`,joinedAt:new Date().toISOString()}}function z(e){return e<1024?`${e} B`:e<1024*1024?`${Math.round(e/1024)} KB`:`${(e/1024/1024).toFixed(1)} MB`}var B={width:420,height:680},V={width:340,height:480},H={width:920,height:860};function U({className:e,title:r=`Messages`,subtitle:i=`ChatEmi`,placement:a=`bottom-right`,defaultOpen:o=!1,showNotificationList:s=!0,badgeCount:c,initialSize:l=B,minSize:u=V,maxSize:d=H,markNotificationsReadOnOpen:f=!0,launcherIcon:p,...m}){let{actions:g,conversations:_,connectionStatus:v,notifications:y,theme:b,unreadNotificationCount:x}=h(),[S,C]=(0,t.useState)(o),[w,E]=(0,t.useState)({x:0,y:0}),D=(0,t.useRef)(void 0),O=(0,t.useMemo)(()=>_.reduce((e,t)=>e+(t.unreadCount??0),0),[_]),k=c??(x>0?x:O);function A(){let e=!S;C(e),e&&(f&&g.markNotificationsRead(),g.requestNotificationPermission())}function j(e){e.target.closest(`button`)||(e.currentTarget.setPointerCapture(e.pointerId),D.current={pointerId:e.pointerId,startX:e.clientX,startY:e.clientY,originX:w.x,originY:w.y})}function M(e){let t=D.current;!t||t.pointerId!==e.pointerId||E({x:t.originX+e.clientX-t.startX,y:t.originY+e.clientY-t.startY})}function N(e){D.current?.pointerId===e.pointerId&&(D.current=void 0)}return(0,n.jsxs)(`div`,{className:[`chatemi-launcher`,`chatemi-launcher--${a}`,e].filter(Boolean).join(` `),"data-theme":m.theme??b,children:[S?(0,n.jsxs)(`section`,{"aria-label":r,className:`chatemi-launcher__modal`,style:{width:l.width,height:l.height,minWidth:u.width,minHeight:u.height,maxWidth:d.width,maxHeight:d.height,transform:`translate(${w.x}px, ${w.y}px)`},children:[(0,n.jsxs)(`div`,{className:`chatemi-launcher__modal-header`,onPointerDown:j,onPointerMove:M,onPointerUp:N,onPointerCancel:N,children:[(0,n.jsxs)(`div`,{children:[(0,n.jsx)(`strong`,{children:r}),(0,n.jsxs)(`span`,{children:[i,` · `,v]})]}),(0,n.jsx)(`button`,{"aria-label":`Close messages`,onClick:A,type:`button`,children:`Close`})]}),s&&y.length>0?(0,n.jsxs)(`div`,{className:`chatemi-launcher__notifications`,"aria-label":`Notifications`,children:[y.slice(0,3).map(e=>(0,n.jsxs)(`button`,{className:e.read?`chatemi-launcher__notification`:`chatemi-launcher__notification chatemi-launcher__notification--unread`,onClick:()=>{e.conversationId&&g.openConversation(e.conversationId),g.markNotificationsRead([e.id])},type:`button`,children:[e.avatarUrl?(0,n.jsx)(`img`,{alt:``,src:e.avatarUrl}):(0,n.jsx)(`span`,{children:e.title.slice(0,2).toUpperCase()}),(0,n.jsxs)(`span`,{children:[(0,n.jsx)(`strong`,{children:e.title}),e.body?(0,n.jsx)(`small`,{children:e.body}):null]})]},e.id)),(0,n.jsx)(`button`,{className:`chatemi-launcher__clear`,onClick:g.clearNotifications,type:`button`,children:`Clear`})]}):null,(0,n.jsx)(T,{...m})]}):null,(0,n.jsxs)(`button`,{"aria-expanded":S,"aria-label":S?`Close messages`:`Open messages`,className:`chatemi-launcher__toggle`,onClick:A,type:`button`,children:[(0,n.jsx)(`span`,{className:`chatemi-launcher__icon`,children:p??(0,n.jsx)(W,{})}),k>0?(0,n.jsx)(`span`,{className:`chatemi-launcher__badge`,children:k>99?`99+`:k}):null]})]})}function W(){return(0,n.jsxs)(`svg`,{"aria-hidden":`true`,fill:`none`,height:`28`,viewBox:`0 0 28 28`,width:`28`,children:[(0,n.jsx)(`path`,{d:`M5 13.4C5 8.76 8.98 5 13.9 5h.2C19.02 5 23 8.76 23 13.4c0 4.62-3.98 8.38-8.9 8.38h-.64c-.42 0-.83.12-1.18.34l-3.54 2.2a.75.75 0 0 1-1.14-.64l.18-3.2a1.8 1.8 0 0 0-.5-1.36A8.06 8.06 0 0 1 5 13.4Z`,stroke:`currentColor`,strokeLinecap:`round`,strokeLinejoin:`round`,strokeWidth:`2`}),(0,n.jsx)(`path`,{d:`M10 12.5h8M10 16h5`,stroke:`currentColor`,strokeLinecap:`round`,strokeWidth:`2`})]})}e.ChatEmiApi=a,e.ChatEmiApiError=i,e.ChatEmiLauncher=U,e.ChatEmiMessenger=T,e.ChatEmiProvider=m,e.ChatEmiSocket=u,e.useChatEmi=h});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mademi_dev/chatemi",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.2",
|
|
4
4
|
"description": "A React messaging kit with API clients, realtime socket support, hooks, provider state, and default Telegram-style UI.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/chatemi.umd.cjs",
|