🚀 Big News: Socket Acquires Coana to Bring Reachability Analysis to Every Appsec Team.Learn more
Socket
Sign inDemoInstall
Socket

@xmtp/react-sdk

Package Overview
Dependencies
Maintainers
6
Versions
85
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@xmtp/react-sdk - npm Package Compare versions

Comparing version

to
6.0.1

41

lib/index.d.ts

@@ -404,2 +404,41 @@ import * as _xmtp_xmtp_js from '@xmtp/xmtp-js';

type SendMessageOptions = Omit<SendOptions, "contentType"> & Pick<UseSendMessageOptions, "onSuccess" | "onError">;
/**
* This hook wraps helper functions to include the client, DB instance, and
* other values for easier consumption.
*/
declare const useMessage: () => {
deleteMessage: (message: CachedMessageWithId<any>) => Promise<void>;
getMessageByXmtpID: (xmtpID: string) => Promise<CachedMessageWithId<any> | undefined>;
processMessage: (conversation: CachedConversation, message: CachedMessage) => Promise<{
status: "processed" | "no_client" | "queued" | "duplicate" | "invalid" | "unsupported";
message: CachedMessage<any, ContentTypeMetadata>;
}>;
resendMessage: (message: CachedMessageWithId) => Promise<_xmtp_xmtp_js.DecodedMessage<any>>;
sendMessage: (conversation: CachedConversation, content: any, contentType?: ContentTypeId, options?: SendMessageOptions) => Promise<{
cachedMessage: CachedMessage<any, ContentTypeMetadata>;
sentMessage: _xmtp_xmtp_js.DecodedMessage<any>;
} | {
cachedMessage: CachedMessage<any, ContentTypeMetadata>;
sentMessage?: undefined;
}>;
updateMessage: (message: CachedMessage<any, ContentTypeMetadata>, update: Partial<Pick<CachedMessage<any, ContentTypeMetadata>, "metadata" | "status" | "isSending" | "sentAt" | "xmtpID" | "hasLoadError" | "hasSendError" | "sendOptions">>) => Promise<{
metadata?: ContentTypeMetadata | undefined;
status: "unprocessed" | "processed";
isSending: boolean;
sentAt: Date;
xmtpID: string;
hasLoadError: boolean;
hasSendError: boolean;
sendOptions?: SendOptions | undefined;
content: any;
contentBytes?: Uint8Array | undefined;
contentFallback?: string | undefined;
contentType: string;
conversationTopic: string;
id?: number | undefined;
senderAddress: string;
uuid: string;
walletAddress: string;
}>;
};

@@ -678,2 +717,2 @@ type UseStartConversation = Partial<InvitationContext> & OnError;

export { type CachedConsentEntry, type CachedConsentEntryMap, type CachedConsentTable, type CachedConversation, type CachedConversationWithId, type CachedConversationsTable, type CachedMessage, type CachedMessageWithId, type CachedMessagesTable, type CachedReaction, type CachedReactionsMetadata, type CachedReactionsTable, type ContentTypeConfiguration, type ContentTypeMessageProcessor, type ContentTypeMessageProcessors, type ContentTypeMessageValidators, type ContentTypeMetadata, type ContentTypeMetadataValue, type ContentTypeMetadataValues, type ProcessUnprocessedMessagesOptions, XMTPProvider, attachmentContentTypeConfig, bulkPutConsentState, clearCache, deleteMessage, getAttachment, getCachedConsentEntries, getCachedConsentEntriesMap, getCachedConsentEntry, getCachedConsentState, getCachedConversationByPeerAddress, getCachedConversationByTopic, getConversationByTopic, getDbInstance, getLastMessage, getMessageByXmtpID, getOriginalMessageFromReply, getReactionsByXmtpID, getReplies, hasConversationTopic, hasReaction, hasReply, isValidAddress, loadConsentListFromCache, putConsentState, reactionContentTypeConfig, replyContentTypeConfig, saveConversation, saveMessage, setConversationUpdatedAt, textContentTypeConfig, toCachedConversation, toCachedMessage, updateConversation, updateConversationMetadata, updateMessage, updateMessageMetadata, useAttachment, useCanMessage, useClient, useConsent, useConversation, useConversations, useDb, useLastMessage, useMessages, useReactions, useReplies, useReply, useResendMessage, useSendMessage, useStartConversation, useStreamAllMessages, useStreamConsentList, useStreamConversations, useStreamMessages };
export { type CachedConsentEntry, type CachedConsentEntryMap, type CachedConsentTable, type CachedConversation, type CachedConversationWithId, type CachedConversationsTable, type CachedMessage, type CachedMessageWithId, type CachedMessagesTable, type CachedReaction, type CachedReactionsMetadata, type CachedReactionsTable, type ContentTypeConfiguration, type ContentTypeMessageProcessor, type ContentTypeMessageProcessors, type ContentTypeMessageValidators, type ContentTypeMetadata, type ContentTypeMetadataValue, type ContentTypeMetadataValues, type ProcessUnprocessedMessagesOptions, XMTPProvider, attachmentContentTypeConfig, bulkPutConsentState, clearCache, deleteMessage, getAttachment, getCachedConsentEntries, getCachedConsentEntriesMap, getCachedConsentEntry, getCachedConsentState, getCachedConversationByPeerAddress, getCachedConversationByTopic, getConversationByTopic, getDbInstance, getLastMessage, getMessageByXmtpID, getOriginalMessageFromReply, getReactionsByXmtpID, getReplies, hasConversationTopic, hasReaction, hasReply, isValidAddress, loadConsentListFromCache, putConsentState, reactionContentTypeConfig, replyContentTypeConfig, saveConversation, saveMessage, setConversationUpdatedAt, textContentTypeConfig, toCachedConversation, toCachedMessage, updateConversation, updateConversationMetadata, updateMessage, updateMessageMetadata, useAttachment, useCanMessage, useClient, useConsent, useConversation, useConversations, useDb, useLastMessage, useMessage, useMessages, useReactions, useReplies, useReply, useResendMessage, useSendMessage, useStartConversation, useStreamAllMessages, useStreamConsentList, useStreamConversations, useStreamMessages };

2

lib/index.js

@@ -1,2 +0,2 @@

import{jsx as e}from"react/jsx-runtime";import{createContext as t,useState as n,useMemo as s,useRef as r,useContext as a,useCallback as o,useEffect as c}from"react";import i from"dexie";import{ContentTypeText as d,decodeContent as l,ConsentListEntry as u,Client as w,SortDirection as p,ContentTypeId as y}from"@xmtp/xmtp-js";export{Client,Compression,ContentTypeId,ContentTypeText,SortDirection}from"@xmtp/xmtp-js";import{isAfter as m,min as v,subSeconds as g}from"date-fns";import{v4 as f}from"uuid";import{Mutex as h}from"async-mutex";import{useLiveQuery as A}from"dexie-react-hooks";import{AttachmentCodec as b,RemoteAttachmentCodec as T,ContentTypeAttachment as M,ContentTypeRemoteAttachment as E}from"@xmtp/content-type-remote-attachment";import{z as S}from"zod";import{ReactionCodec as D,ContentTypeReaction as x}from"@xmtp/content-type-reaction";import{ReplyCodec as I,ContentTypeReply as C}from"@xmtp/content-type-reply";const X={codecs:[],contentTypes:[d.toString()],namespace:"text",validators:{[d.toString()]:e=>"string"==typeof e}},P=e=>{const t=e?.db??new i("__XMTP__");if(!t.isOpen()){const n=e?.contentTypeConfigs?.reduce(((e,{schema:t})=>({...e,...t})),{}),s=e?.version??1;t.version(s).stores({...n,conversations:"\n ++id,\n [walletAddress+topic],\n [walletAddress+peerAddress],\n createdAt,\n peerAddress,\n topic,\n updatedAt,\n walletAddress\n ",messages:"\n ++id,\n [conversationTopic+walletAddress],\n contentFallback,\n contentType,\n conversationTopic,\n senderAddress,\n sentAt,\n status,\n uuid,\n walletAddress,\n xmtpID\n ",consent:"\n [walletAddress+peerAddress],\n peerAddress,\n state,\n walletAddress\n "})}return t},L=async e=>{await Promise.all(e.tables.map((e=>e.clear())))},q=[X],B=new i("__XMTP__"),O=t({codecs:[],db:B,namespaces:{},processors:{},setClient:()=>{},validators:{}}),_=({children:t,client:r,contentTypeConfigs:a,dbVersion:o})=>{const[c,i]=n(r),d=s((()=>(e=>({...[...q,...e??[]].reduce(((e,t)=>{const n=Object.entries(t.processors??[]).reduce(((t,[n,s])=>({...t,[n]:[...e[n]??[],...s]})),{});return{...e,...n}}),{})}))(a??[])),[a]),l=s((()=>(e=>[...q,...e??[]].reduce(((e,t)=>[...e,...t.codecs??[]]),[]))(a??[])),[a]),u=s((()=>(e=>{const t=[...q,...e??[]],n=[];return t.reduce(((e,t)=>{if(n.includes(t.namespace))throw new Error(`Duplicate content types config namespace detected: "${t.namespace}"`);return n.push(t.namespace),{...e,...(t.contentTypes??[]).reduce(((e,n)=>({...e,[n]:t.namespace})),{})}}),{})})(a??[])),[a]),w=s((()=>(e=>{const t=[...q,...e??[]],n=[];return t.reduce(((e,t)=>{const s={};return Object.entries(t.validators??{}).forEach((([e,t])=>{if(n.includes(e))throw new Error(`Duplicate content validator detected for content type "${e}"`);n.push(e),s[e]=t})),{...e,...s}}),{})})(a??[])),[a]),p=s((()=>P({db:B,contentTypeConfigs:a,version:o})),[o,a]),y=s((()=>({client:c,codecs:l,db:p,namespaces:u,processors:d,setClient:i,validators:w})),[c,l,p,u,d,w]);return e(O.Provider,{value:y,children:t})},j=e=>e.startsWith("0x")&&42===e.length,k=async(e,t,n,s)=>{const r=s.table("conversations"),a=await r.where({walletAddress:e,[t]:n}).first();return a||void 0},R=async(e,t,n)=>k(e,"topic",t,n),U=async(e,t,n)=>k(e,"peerAddress",t,n),F=async(e,t)=>{let n;return(await t.conversations.listFromCache()).some((t=>t.topic===e&&(n=t,!0))),n},N=async(e,t,n)=>{const s=n.table("conversations"),r=await s.where("topic").equals(e).first();r&&await s.update(r,t)},z=async(e,t,n,s,r)=>{const a=await R(e,t,r);if(a){const e=a.metadata||{};e[n]=s,await N(t,{metadata:e},r)}},G=async(e,t,n)=>{await N(e,{updatedAt:t},n)},$=async(e,t,n)=>!!await R(e,t,n),K=(e,t)=>({context:e.context,createdAt:e.createdAt,isReady:!1,peerAddress:e.peerAddress,topic:e.topic,updatedAt:e.createdAt,walletAddress:t}),V=new h,W=async(e,t)=>V.runExclusive((async()=>{const n=t.table("conversations"),s=await n.where({walletAddress:e.walletAddress,topic:e.topic}).first();return s||(e.id=await n.add(e),e)})),H=(e,t)=>{const n=void 0!==e.content;return{content:e.content,contentBytes:n?void 0:e.contentBytes,contentFallback:e.contentFallback,contentType:e.contentType.toString(),conversationTopic:e.contentTopic,status:"unprocessed",hasLoadError:!1,hasSendError:!1,isSending:!1,senderAddress:e.senderAddress,sentAt:e.sent,uuid:f(),walletAddress:t,xmtpID:e.id}},J=async(e,t)=>{const n=t.table("messages"),s=await n.where("xmtpID").equals(e).first();return s||void 0},Q=async(e,t)=>{const n=t.table("messages"),s=await J(e.xmtpID,t);if(s)return s;const r=await n.add(e);return{...e,id:r}},Y=async(e,t)=>{const n=t.table("messages");await n.where("id").equals(e.id).first()&&await n.delete(e.id)},Z=async(e,t,n)=>{const s=n.table("messages");return await s.update(e,t),{...e,...t}},ee=async(e,t,n,s)=>{const r=e.metadata||{};return r[t]=n,Z(e,{metadata:r},s)},te=[],ne=async({client:e,conversation:t,db:n,message:s,namespaces:r,processors:a,validators:o},c=!1)=>{if(!e)return{status:"no_client",message:s};if(te.includes(s.xmtpID))return{status:"queued",message:s};te.push(s.xmtpID);const i=r[s.contentType];try{const r=await J(s.xmtpID,n);if(r&&"processed"===r.status)return{status:"duplicate",message:s};const d=o[s.contentType];if(d&&!d(s.content))return{status:"invalid",message:s};const l=async s=>{await z(e.address,t.topic,i,s,n)};if(void 0===s.content)return{status:"unsupported",message:r?s:await Q(s,n)};c&&r&&await Y(r,n),a[s.contentType]&&await Promise.all(a[s.contentType].map((r=>r({client:e,conversation:t,db:n,message:s,processors:a,updateConversationMetadata:l}))));const u=await Q(s,n);!s.isSending&&m(s.sentAt,t.updatedAt)&&await G(t.topic,s.sentAt,n);return{status:"processed",message:await Z(u,{status:"processed"},n)}}finally{const e=te.indexOf(s.xmtpID);e>-1&&te.splice(e,1)}},se=async({client:e,conversation:t,db:n,message:s,namespaces:r,processors:a,validators:o,process:c=ne,decode:i=l})=>{if(void 0===s.content&&s.contentBytes&&e&&a[s.contentType]){const d=await i(s.contentBytes,e);return void 0===d.content?s:c({conversation:t,client:e,db:n,message:{...s,content:d.content,contentBytes:void 0},namespaces:r,processors:a,validators:o},!0)}return s},re=async(e,t)=>{const n=t.table("messages");return(await n.where({conversationTopic:e}).reverse().sortBy("sentAt"))[0]},ae=async(e,t,n)=>n.table("consent").where({walletAddress:e,peerAddress:t}).first(),oe=async(e,t)=>{const n=t.table("consent");return(await n.where({walletAddress:e}).toArray()).map((e=>u.fromAddress(e.peerAddress,e.state)))},ce=async(e,t)=>{const n=await oe(e,t);return n.length?Object.fromEntries(n.map((e=>[e.value,e]))):{}},ie=async(e,t,n)=>{const s=await ae(e,t,n);return s?.state??"unknown"},de=async(e,t)=>{const n=await oe(e.address,t);e.contacts.setConsentListEntries(n)},le=new h,ue=async(e,t,n,s)=>le.runExclusive((async()=>{const r=s.table("consent");await r.put({peerAddress:t,state:n,walletAddress:e})})),we=async(e,t)=>le.runExclusive((async()=>{const n=t.table("consent");await n.bulkPut(e)})),pe=e=>{const[t,s]=n(!1),[c,i]=n(null),d=r(!1),{client:l,setClient:u,codecs:p,db:y,processors:m,namespaces:v,validators:g}=a(O),f=o((async({keys:t,options:n,signer:r})=>{if(!l&&(r||t)){if(d.current)return;let a;d.current=!0,i(null),s(!0);try{a=await w.create(r??null,{...n,codecs:p,privateKeyOverride:t}),u(a)}catch(t){throw u(void 0),i(t),e?.(t),t}finally{d.current=!1}s(!1);try{await de(a,y)}catch(t){e?.(t)}try{await(async({client:e,db:t,namespaces:n,processors:s,validators:r,reprocess:a=se})=>{const o=await(async e=>{const t=e.table("messages");return await t.where({status:"unprocessed"}).toArray()})(t);await Promise.all(o.map((async o=>{const c=await R(e.address,o.conversationTopic,t);c&&await a({conversation:c,client:e,db:t,message:o,namespaces:n,processors:s,validators:r})})))})({client:a,db:y,processors:m,namespaces:v,validators:g})}catch(t){e?.(t)}return d.current=!1,a}return l}),[l,p,y,v,e,m,u,g]),h=o((async()=>{l&&(await l.close(),u(void 0))}),[l,u]);return{client:l,disconnect:h,error:c,initialize:f,isLoading:t}},ye=()=>{const e=a(O),{db:t}=e;return{clearCache:o((async()=>{await L(t)}),[t]),db:t}},me=()=>{const{client:e}=pe(),{db:t}=ye();return{saveConversation:o((n=>e?W(n,t):void 0),[e,t]),updateConversation:o((async(e,n)=>{await N(e,n,t)}),[t]),updateMetadata:o((async(n,s,r)=>{e&&await z(e.address,n,s,r,t)}),[e,t])}},ve=()=>{const{client:e}=pe(),{db:t}=ye();return{getByTopic:o((async t=>e?F(t,e):void 0),[e]),getCachedByTopic:o((async n=>e?R(e.address,n,t):void 0),[e,t]),getCachedByPeerAddress:o((async n=>e?U(e.address,n,t):void 0),[e,t]),getLastMessage:o((async e=>re(e,t)),[t]),hasConversationTopic:o((async n=>!!e&&$(e.address,n,t)),[e,t])}},ge=()=>{const e=a(O),{processors:t,namespaces:n,validators:s}=e,{client:r}=pe(),{db:c}=ye(),i=o((async(e,a)=>ne({client:r,conversation:e,db:c,message:a,namespaces:n,processors:t,validators:s})),[r,c,n,t,s]),l=o((async(e,t)=>Z(e,t,c)),[c]),u=o((async(e,t)=>(async(e,t,n)=>Z(e,{hasSendError:!1,isSending:!1,sendOptions:void 0,sentAt:t},n))(e,t,c)),[c]),w=o((async e=>J(e,c)),[c]),p=o((async e=>Y(e,c)),[c]),y=o((async(e,t,n,s)=>{if(!r)throw new Error("XMTP client is required to send a message");if(void 0===t)throw new Error("Message content is required to send a message");const{onSuccess:a,onError:o,...w}=s??{},p={...w,contentType:n??d};try{const{message:n,preparedMessage:s}=await(async({client:e,content:t,conversation:n,sendOptions:s})=>{const r=await F(n.topic,e);if(!r)throw new Error("Conversation not found in XMTP client, unable to prepare message");const a=await r.prepareMessage(t,s),o=new Date;return{message:{content:t,contentType:s?.contentType?.toString()??d.toString(),conversationTopic:n.topic,hasLoadError:!1,hasSendError:!1,isSending:!0,senderAddress:e.address,sentAt:o,status:"unprocessed",uuid:f(),walletAddress:e.address,xmtpID:await a.messageID()},preparedMessage:a}})({client:r,content:t,conversation:e,sendOptions:p}),{status:o,message:w}=await i(e,n);switch(o){case"invalid":throw new Error("Unable to send message: content is invalid");case"duplicate":throw new Error("Unable to send message: message is a duplicate")}if("processed"===o)try{const t=await s.send();return await G(e.topic,t.sent,c),a?.(t),w.id&&await u(w,t.sent),{cachedMessage:w,sentMessage:t}}catch(e){throw w.id&&await l(w,{hasSendError:!0,sendOptions:p}),e}return{cachedMessage:w}}catch(e){throw o?.(e),e}}),[r,c,i,l,u]),m=o((async e=>{if(!e.hasSendError)throw new Error("Resending a message that hasn't failed to send is not allowed");if(!r)throw new Error("XMTP client is required to send a message");const t=await F(e.conversationTopic,r);if(!t){throw new Error("Conversation not found in XMTP client, unable to send message")}const n=await t.send(e.content,e.sendOptions);return await G(t.topic,n.sent,c),await u(e,n.sent),n}),[r,c,u]);return{deleteMessage:p,getMessageByXmtpID:w,processMessage:i,resendMessage:m,sendMessage:y,updateMessage:l}},fe=e=>{const[t,s]=n(!1),[a,o]=n(!1),[i,d]=n(null),{client:l}=pe(),{processMessage:u}=ge(),{saveConversation:w}=me(),{hasConversationTopic:y}=ve(),m=(()=>{const{db:e}=ye(),{client:t}=pe();return A((async()=>t?e.table("conversations").where("walletAddress").equals(t.address).reverse().sortBy("updatedAt"):[]),[t?.address])??[]})(),v=r(!1),{onConversations:g,onError:f}=e??{};return c((()=>{if(!l){const e=new Error("XMTP client is required to fetch conversations");return d(e),void f?.(e)}(async()=>{if(!v.current){v.current=!0,s(!0),o(!1),d(null);try{const e=await l.conversations.list()??[];await Promise.all(e.map((async e=>{if(!await y(e.topic)){const t=await w(K(e,l.address)),n=await e.messages({direction:p.SORT_DIRECTION_DESCENDING,limit:1});if(n.length>0&&t){const e=n[0];await u(t,H(e,l.address))}}}))),o(!0),g?.(e)}catch(e){throw d(e),f?.(e),e}finally{s(!1),v.current=!1}}})()}),[g,f,l,w,u,y]),{conversations:m,error:i,isLoaded:a,isLoading:t}},he=e=>{const[t,s]=n(!1),[r,a]=n(null),{client:c}=pe(),{sendMessage:i}=ge(),{saveConversation:d}=me(),{conversationId:l,metadata:u,onError:w}=e??{};return{error:r,isLoading:t,startConversation:o((async(e,t,n,r)=>{if(void 0===c){const e=new Error("XMTP client is required to start a conversation");return a(e),w?.(e),{cachedConversation:void 0,cachedMessage:void 0,conversation:void 0}}s(!0),a(null);try{const s=await c.conversations.newConversation(e,l&&u?{conversationId:l,metadata:u}:void 0),a=await d(K(s,c.address));if(!a)return{cachedConversation:void 0,cachedMessage:void 0,conversation:s};if(void 0===t)return{cachedConversation:a,cachedMessage:void 0,conversation:s};const{cachedMessage:o}=await i(a,t,n,r);return{cachedConversation:a,cachedMessage:o,conversation:s}}catch(e){throw a(e),w?.(e),e}finally{s(!1)}}),[i,c,l,u,w,d])}},Ae=e=>{const[t,s]=n(null),a=r(void 0),o=r((async e=>{a.current&&(a.current=void 0),void 0!==e&&(await e).return()})),{client:i}=pe(),{saveConversation:d}=me(),{onConversation:l,onError:u}=e??{};return c((()=>{let e=a.current;const t=o.current;return(async()=>{if(!a.current){if(void 0===i){const e=new Error("XMTP client is not available");return s(e),void u?.(e)}try{if(a.current)return;a.current=i.conversations.stream(),e=a.current;for await(const t of await e)await d(K(t,i.address)),l?.(t)}catch(n){throw s(n),u?.(n),t(e),n}}})(),()=>{t(e)}}),[i,d,u,l]),{error:t}},be=e=>{const{db:t}=ye();return A((async()=>{const n=t.table("messages");return(await n.where({conversationTopic:e}).reverse().sortBy("sentAt")).filter((e=>void 0!==e.content))[0]}),[e])},Te=e=>{const[t,s]=n(!1),[r,a]=n(null),{client:c}=pe();return{error:r,isLoading:t,canMessage:o((async t=>{if(!c)throw new Error("XMTP client is required to check if an address is on the network");s(!1),a(null);try{return await c.canMessage(t)}catch(t){throw a(t),e?.(t),t}finally{s(!1)}}),[c,e]),canMessageStatic:o((async(t,n)=>{s(!1),a(null);try{return await w.canMessage(t,n)}catch(t){throw a(t),e?.(t),t}finally{s(!1)}}),[e])}},Me=(e,t)=>{const[s,a]=n(!1),[i,d]=n(!1),[l,u]=n(null),{processMessage:w}=ge(),{updateConversation:y}=me(),m=(e=>{const{db:t}=ye(),{client:n}=pe();return A((async()=>n?t.table("messages").where({conversationTopic:e,walletAddress:n.address}).sortBy("sentAt"):[]),[e])??[]})(e.topic),{client:f}=pe(),h=r(!1),{disableAutoSync:b,onError:T,onMessages:M}=t??{},E=o((async()=>{if(h.current)return;if(!f){const e=new Error("XMTP client is not available");return u(e),void T?.(e)}let t;if(h.current=!0,d(!0),a(!1),u(null),e.isReady){const n=v([e.lastSyncedAt??Date.now(),e.updatedAt]);t=g(n,10)}try{const n=await F(e.topic,f),s=new Date,r=await(n?.messages({direction:p.SORT_DIRECTION_ASCENDING,startTime:t}))??[];await Promise.all(r.map((t=>w(e,H(t,f.address))))),e.isReady||await y(e.topic,{isReady:!0}),await y(e.topic,{lastSyncedAt:s}),a(!0),M?.(r)}catch(e){throw u(e),T?.(e),e}finally{d(!1),h.current=!1}}),[f,e,T,M,w,y]);return c((()=>{E()}),[E]),c((()=>{const e=()=>{document.hidden||b||E()};return document.addEventListener("visibilitychange",e),()=>{document.removeEventListener("visibilitychange",e)}}),[E,b]),{error:l,isLoaded:s,isLoading:i,messages:m}},Ee=()=>{const{client:e}=pe(),{db:t}=ye(),n=(()=>{const{db:e}=ye(),{client:t}=pe();return A((async()=>t?ce(t.address,e):{}),[t?.address])??{}})(),s=o((async(n,s=!1)=>{if(!e)throw new Error("XMTP client is required");s||await e.contacts.allow(n),await we(n.map((t=>({peerAddress:t,state:"allowed",walletAddress:e.address}))),t)}),[e,t]),r=o((async(n,s=!1)=>{if(!e)throw new Error("XMTP client is required");s||await e.contacts.deny(n),await we(n.map((t=>({peerAddress:t,state:"denied",walletAddress:e.address}))),t)}),[e,t]);return{allow:s,consentState:o((async n=>{if(!e)throw new Error("XMTP client is required");return ie(e.address,n,t)}),[e,t]),deny:r,entries:n,isAllowed:o((async n=>{if(!e)throw new Error("XMTP client is required");return"allowed"===await ie(e.address,n,t)}),[e,t]),isDenied:o((async n=>{if(!e)throw new Error("XMTP client is required");return"denied"===await ie(e.address,n,t)}),[e,t]),loadConsentList:o((async n=>{if(!e)throw new Error("XMTP client is required");const s=await e.contacts.loadConsentList(n);return s.length>0&&await we(s.map((t=>({peerAddress:t.value,state:t.permissionType,walletAddress:e.address}))),t),s}),[e,t]),refreshConsentList:o((async()=>{if(!e)throw new Error("XMTP client is required");await t.table("consent").clear();const n=await(e?.contacts.refreshConsentList());return n.length>0&&await we(n.map((t=>({peerAddress:t.value,state:t.permissionType,walletAddress:e.address}))),t),n}),[e,t])}},Se=e=>{const[t,s]=n(!1),[r,a]=n(null),{sendMessage:c}=ge(),{allow:i,consentState:d}=Ee(),{onError:l,onSuccess:u}=e??{};return{error:r,isLoading:t,sendMessage:o((async(e,t,n,r)=>{s(!0),a(null);try{const{sentMessage:s}=await c(e,t,n,{...r,onSuccess:u,onError:l});return"allowed"!==await d(e.peerAddress)&&await i([e.peerAddress],!0),s}catch(e){throw a(e),e}finally{s(!1)}}),[c,i,d,l,u])}},De=e=>{const[t,s]=n(!1),[r,a]=n(null),{resendMessage:c,deleteMessage:i}=ge(),{onError:d,onSuccess:l}=e??{},u=o((async e=>{s(!0),a(null);try{const t=await c(e);return l?.(t),t}catch(e){throw a(e),d?.(e),e}finally{s(!1)}}),[c,d,l]);return{cancel:o((async e=>{try{await i(e)}catch(e){throw a(e),d?.(e),e}}),[i,d]),error:r,isLoading:t,resend:u}},xe=(e,t)=>{const[s,a]=n(null),o=r(void 0),i=r((async e=>{o.current&&(o.current=void 0),void 0!==e&&(await e).return(void 0)})),{processMessage:d}=ge(),{getCachedByTopic:l}=ve(),{client:u}=pe();return c((()=>{let n=o.current;const s=i.current;return(async()=>{if(!o.current){if(void 0===u){const e=new Error("XMTP client is not available");return a(e),void t?.(e)}try{if(o.current)return;o.current=u.conversations.streamAllMessages(),n=o.current;for await(const t of await n){const n=await l(t.conversation.topic);n&&await d(n,H(t,u.address)),e?.(t)}}catch(e){throw a(e),t?.(e),s(n),e}}})(),()=>{s(n)}}),[e,u,t,d,l]),{error:s}},Ie=(e,t)=>{const[s,a]=n(null),o=r(void 0),i=r((async e=>{o.current&&(o.current=void 0),void 0!==e&&(await e).return()})),{processMessage:d}=ge(),{client:l}=pe(),{onError:u,onMessage:w}=t??{};return c((()=>{if(!e||!l){const e=new Error("XMTP client and/or conversation is not available");return a(e),u?.(e),()=>{}}let t=o.current;const n=i.current;return(async()=>{if(o.current)return;const s=await F(e.topic,l);if(s)try{if(o.current)return;o.current=s.streamMessages(),t=o.current;for await(const n of await t)await d(e,H(n,l.address)),w?.(n)}catch(e){throw a(e),u?.(e),n(t),e}})(),()=>{n(t)}}),[l,e,u,w,d]),{error:s}},Ce=(e,t)=>{const{allow:s,deny:a}=Ee(),[o,i]=n(null),d=r(void 0),l=r((async e=>{d.current&&(d.current=void 0),void 0!==e&&(await e).return()})),{client:u}=pe();return c((()=>{let n=d.current;const r=l.current;return(async()=>{if(!d.current){if(void 0===u){const e=new Error("XMTP client is not available");return i(e),void t?.(e)}try{if(d.current)return;d.current=u.contacts.streamConsentList(),n=d.current;for await(const t of await n)t.allowAddress&&s(t.allowAddress.walletAddresses,!0),t.denyAddress&&a(t.denyAddress.walletAddresses,!0),e?.(t)}catch(e){throw i(e),t?.(e),r(n),e}}})(),()=>{r(n)}}),[u,t,e,s,a]),{error:o}},Xe="attachment",Pe=e=>{switch(e.contentType){case M.toString():case E.toString():return e.content;default:return}},Le=S.object({filename:S.string(),mimeType:S.string(),data:S.instanceof(Uint8Array)}),qe=S.object({url:S.string(),contentDigest:S.string(),salt:S.instanceof(Uint8Array),nonce:S.instanceof(Uint8Array),secret:S.instanceof(Uint8Array),scheme:S.string(),contentLength:S.number().gte(0),filename:S.string()}),Be={codecs:[new b,new T],contentTypes:[M.toString(),E.toString()],namespace:Xe,validators:{[M.toString()]:e=>{const{success:t}=Le.safeParse(e);return t},[E.toString()]:e=>{const{success:t}=qe.safeParse(e);return t}}},Oe=10485760,_e=(e,t)=>{const{client:a}=pe(),{db:i}=ye(),{updateMessage:d}=ge(),[l,u]=n(void 0),[w,p]=n("init"),[y,m]=n(void 0),v=r(!1),{disableAutoload:g=!1,autoloadMaxFileSize:f=Oe}=t??{},h=s((()=>(e=>{if(e.contentType===E.toString()){const t=e.metadata?.[Xe];return t}})(e)),[e]),A=o((async(t=!1)=>{if(h&&"loaded"!==w)return m(h),void p("loaded");if(a&&e.contentType===E.toString()&&!h&&"loading"!==w&&"loaded"!==w&&!y&&(e.hasLoadError&&t||!e.hasLoadError))try{p("loading");const t=await T.load(e.content,a);try{await(async(e,t,n)=>{e.contentType===E.toString()&&await ee(e,Xe,t,n)})(e,t,i)}catch{}m(t),p("loaded")}catch(t){await d(e,{hasLoadError:!0}),u(new Error("Unable to load remote attachment")),p("error")}else u(new Error("XMTP client is required to load remote attachments")),p("error")}),[h,w,a,e,y,i,d]),b=o((()=>{A(!0)}),[A]);return c((()=>{(async()=>{if(!v.current&&(v.current=!0,!y&&"loading"!==w&&"loaded"!==w))switch(e.contentType){case M.toString():m(e.content),p("loaded"),v.current=!1;break;case E.toString():if(h)return m(h),p("loaded"),void(v.current=!1);if(e.content.contentLength>f)return p("autoloadMaxFileSizeExceeded"),void(v.current=!1);g||await A(),v.current=!1;break;default:u(new Error("Message is not an attachment content type")),p("error"),v.current=!1}})()}),[h,f,i,g,A,e,y,w]),{attachment:y,error:l,load:b,status:w}},je=e=>{const{db:t}=ye();return A((async()=>{if(!e)return[];try{const n=t.table("reactions");return await n.where("referenceXmtpID").equals(e.xmtpID).sortBy("sentAt")}catch{return[]}}),[e])??[]},ke="reactions",Re=async(e,t)=>{const n=t.table("reactions"),s={content:e.content,referenceXmtpID:e.referenceXmtpID,schema:e.schema,senderAddress:e.senderAddress},r=await n.where(s).first();return r||void 0},Ue=async(e,t)=>t.table("reactions").where({referenceXmtpID:e}).sortBy("sentAt"),Fe=e=>!!e?.metadata?.[ke],Ne=S.object({reference:S.string(),action:S.enum(["added","removed"]),content:S.string(),schema:S.enum(["unicode","shortcode","custom"])}),ze=e=>{const{success:t}=Ne.safeParse(e);return t},Ge=new h,$e={codecs:[new D],contentTypes:[x.toString()],namespace:ke,processors:{[x.toString()]:[async({message:e,db:t})=>{await Ge.runExclusive((async()=>{const n=y.fromString(e.contentType);if(x.sameAs(n)&&ze(e.content)){const n=e.content,s={content:n.content,referenceXmtpID:n.reference,schema:n.schema,senderAddress:e.senderAddress,sentAt:e.sentAt,xmtpID:e.xmtpID};switch(n.action){case"added":await(async(e,t)=>{const n=t.table("reactions"),s=await Re(e,t);return s?(await n.update(s.id,{sentAt:e.sentAt}),s.id):n.add(e)})(s,t);break;case"removed":await(async(e,t)=>{const n=t.table("reactions"),s=await Re(e,t);s&&await n.delete(s.id)})(s,t)}await(async(e,t)=>{const n=await Ue(e,t),s=await J(e,t);s&&await ee(s,ke,n.length>0,t)})(n.reference,t)}}))}]},schema:{reactions:"\n ++id,\n [content+referenceXmtpID+schema+senderAddress],\n referenceXmtpID,\n content,\n schema,\n senderAddress,\n sentAt,\n xmtpID\n "},validators:{[x.toString()]:ze}},Ke=async(e,t)=>{const n=t.table("replies"),s=await n.where({referenceXmtpID:e.xmtpID}).toArray();if(s.length>0){const e=t.table("messages");return await e.where("xmtpID").anyOf(s.map((e=>e.xmtpID))).sortBy("sentAt")}return[]},Ve=async(e,t)=>{const n=t.table("replies");return(await n.where({referenceXmtpID:e.xmtpID}).toArray()).length>0},We=async(e,t)=>{if(C.sameAs(y.fromString(e.contentType))&&"processed"===e.status&&e.content){const n=e.content;return J(n.reference,t)}},He=S.object({content:S.any(),contentType:S.object({authorityId:S.string(),typeId:S.string(),versionMajor:S.number().gt(0),versionMinor:S.number().gte(0)}),reference:S.string()}),Je=e=>{const{success:t}=He.safeParse(e);return t},Qe={codecs:[new I],contentTypes:[C.toString()],namespace:"replies",processors:{[C.toString()]:[async({message:e,db:t})=>{const n=y.fromString(e.contentType);if(C.sameAs(n)&&Je(e.content)){const n=e.content;await(async(e,t,n)=>{const s=n.table("replies"),r=await s.where({referenceXmtpID:e,xmtpID:t}).first();return r?r.id:s.add({referenceXmtpID:e,xmtpID:t})})(n.reference,e.xmtpID,t)}}]},schema:{replies:"\n ++id,\n [referenceXmtpID+xmtpID],\n referenceXmtpID,\n xmtpID\n "},validators:{[C.toString()]:Je}},Ye=e=>{const{db:t}=ye(),[s,r]=n(void 0);return c((()=>{(async()=>{if(e){const n=await We(e,t);n&&r(n)}})()}),[t,e]),{originalMessage:s}},Ze=e=>{const{db:t}=ye();return A((async()=>{if(!e)return[];try{return await Ke(e,t)}catch{return[]}}),[e])??[]};export{_ as XMTPProvider,Be as attachmentContentTypeConfig,we as bulkPutConsentState,L as clearCache,Y as deleteMessage,Pe as getAttachment,oe as getCachedConsentEntries,ce as getCachedConsentEntriesMap,ae as getCachedConsentEntry,ie as getCachedConsentState,U as getCachedConversationByPeerAddress,R as getCachedConversationByTopic,F as getConversationByTopic,P as getDbInstance,re as getLastMessage,J as getMessageByXmtpID,We as getOriginalMessageFromReply,Ue as getReactionsByXmtpID,Ke as getReplies,$ as hasConversationTopic,Fe as hasReaction,Ve as hasReply,j as isValidAddress,de as loadConsentListFromCache,ue as putConsentState,$e as reactionContentTypeConfig,Qe as replyContentTypeConfig,W as saveConversation,Q as saveMessage,G as setConversationUpdatedAt,X as textContentTypeConfig,K as toCachedConversation,H as toCachedMessage,N as updateConversation,z as updateConversationMetadata,Z as updateMessage,ee as updateMessageMetadata,_e as useAttachment,Te as useCanMessage,pe as useClient,Ee as useConsent,ve as useConversation,fe as useConversations,ye as useDb,be as useLastMessage,Me as useMessages,je as useReactions,Ze as useReplies,Ye as useReply,De as useResendMessage,Se as useSendMessage,he as useStartConversation,xe as useStreamAllMessages,Ce as useStreamConsentList,Ae as useStreamConversations,Ie as useStreamMessages};
import{jsx as e}from"react/jsx-runtime";import{createContext as t,useState as n,useMemo as s,useRef as r,useContext as a,useCallback as o,useEffect as c}from"react";import i from"dexie";import{ContentTypeText as d,decodeContent as l,ConsentListEntry as u,Client as w,SortDirection as p,ContentTypeId as y}from"@xmtp/xmtp-js";export{Client,Compression,ContentTypeId,ContentTypeText,SortDirection}from"@xmtp/xmtp-js";import{isAfter as m,min as v,subSeconds as g}from"date-fns";import{v4 as f}from"uuid";import{Mutex as h}from"async-mutex";import{useLiveQuery as A}from"dexie-react-hooks";import{AttachmentCodec as b,RemoteAttachmentCodec as T,ContentTypeAttachment as M,ContentTypeRemoteAttachment as E}from"@xmtp/content-type-remote-attachment";import{z as S}from"zod";import{ReactionCodec as D,ContentTypeReaction as x}from"@xmtp/content-type-reaction";import{ReplyCodec as I,ContentTypeReply as C}from"@xmtp/content-type-reply";const X={codecs:[],contentTypes:[d.toString()],namespace:"text",validators:{[d.toString()]:e=>"string"==typeof e}},P=e=>{const t=e?.db??new i("__XMTP__");if(!t.isOpen()){const n=e?.contentTypeConfigs?.reduce(((e,{schema:t})=>({...e,...t})),{}),s=e?.version??1;t.version(s).stores({...n,conversations:"\n ++id,\n [walletAddress+topic],\n [walletAddress+peerAddress],\n createdAt,\n peerAddress,\n topic,\n updatedAt,\n walletAddress\n ",messages:"\n ++id,\n [conversationTopic+walletAddress],\n contentFallback,\n contentType,\n conversationTopic,\n senderAddress,\n sentAt,\n status,\n uuid,\n walletAddress,\n xmtpID\n ",consent:"\n [walletAddress+peerAddress],\n peerAddress,\n state,\n walletAddress\n "})}return t},L=async e=>{await Promise.all(e.tables.map((e=>e.clear())))},q=[X],B=new i("__XMTP__"),O=t({codecs:[],db:B,namespaces:{},processors:{},setClient:()=>{},validators:{}}),_=({children:t,client:r,contentTypeConfigs:a,dbVersion:o})=>{const[c,i]=n(r),d=s((()=>(e=>({...[...q,...e??[]].reduce(((e,t)=>{const n=Object.entries(t.processors??[]).reduce(((t,[n,s])=>({...t,[n]:[...e[n]??[],...s]})),{});return{...e,...n}}),{})}))(a??[])),[a]),l=s((()=>(e=>[...q,...e??[]].reduce(((e,t)=>[...e,...t.codecs??[]]),[]))(a??[])),[a]),u=s((()=>(e=>{const t=[...q,...e??[]],n=[];return t.reduce(((e,t)=>{if(n.includes(t.namespace))throw new Error(`Duplicate content types config namespace detected: "${t.namespace}"`);return n.push(t.namespace),{...e,...(t.contentTypes??[]).reduce(((e,n)=>({...e,[n]:t.namespace})),{})}}),{})})(a??[])),[a]),w=s((()=>(e=>{const t=[...q,...e??[]],n=[];return t.reduce(((e,t)=>{const s={};return Object.entries(t.validators??{}).forEach((([e,t])=>{if(n.includes(e))throw new Error(`Duplicate content validator detected for content type "${e}"`);n.push(e),s[e]=t})),{...e,...s}}),{})})(a??[])),[a]),p=s((()=>P({db:B,contentTypeConfigs:a,version:o})),[o,a]),y=s((()=>({client:c,codecs:l,db:p,namespaces:u,processors:d,setClient:i,validators:w})),[c,l,p,u,d,w]);return e(O.Provider,{value:y,children:t})},j=e=>e.startsWith("0x")&&42===e.length,k=async(e,t,n,s)=>{const r=s.table("conversations"),a=await r.where({walletAddress:e,[t]:n}).first();return a||void 0},R=async(e,t,n)=>k(e,"topic",t,n),U=async(e,t,n)=>k(e,"peerAddress",t,n),F=async(e,t)=>{let n;return(await t.conversations.listFromCache()).some((t=>t.topic===e&&(n=t,!0))),n},N=async(e,t,n)=>{const s=n.table("conversations"),r=await s.where("topic").equals(e).first();r&&await s.update(r,t)},z=async(e,t,n,s,r)=>{const a=await R(e,t,r);if(a){const e=a.metadata||{};e[n]=s,await N(t,{metadata:e},r)}},G=async(e,t,n)=>{await N(e,{updatedAt:t},n)},$=async(e,t,n)=>!!await R(e,t,n),K=(e,t)=>({context:e.context,createdAt:e.createdAt,isReady:!1,peerAddress:e.peerAddress,topic:e.topic,updatedAt:e.createdAt,walletAddress:t}),V=new h,W=async(e,t)=>V.runExclusive((async()=>{const n=t.table("conversations"),s=await n.where({walletAddress:e.walletAddress,topic:e.topic}).first();return s||(e.id=await n.add(e),e)})),H=(e,t)=>{const n=void 0!==e.content;return{content:e.content,contentBytes:n?void 0:e.contentBytes,contentFallback:e.contentFallback,contentType:e.contentType.toString(),conversationTopic:e.contentTopic,status:"unprocessed",hasLoadError:!1,hasSendError:!1,isSending:!1,senderAddress:e.senderAddress,sentAt:e.sent,uuid:f(),walletAddress:t,xmtpID:e.id}},J=async(e,t)=>{const n=t.table("messages"),s=await n.where("xmtpID").equals(e).first();return s||void 0},Q=async(e,t)=>{const n=t.table("messages"),s=await J(e.xmtpID,t);if(s)return s;const r=await n.add(e);return{...e,id:r}},Y=async(e,t)=>{const n=t.table("messages");await n.where("id").equals(e.id).first()&&await n.delete(e.id)},Z=async(e,t,n)=>{const s=n.table("messages");return await s.update(e,t),{...e,...t}},ee=async(e,t,n,s)=>{const r=e.metadata||{};return r[t]=n,Z(e,{metadata:r},s)},te=[],ne=async({client:e,conversation:t,db:n,message:s,namespaces:r,processors:a,validators:o},c=!1)=>{if(!e)return{status:"no_client",message:s};if(te.includes(s.xmtpID))return{status:"queued",message:s};te.push(s.xmtpID);const i=r[s.contentType];try{const r=await J(s.xmtpID,n);if(r&&"processed"===r.status)return{status:"duplicate",message:s};const d=o[s.contentType];if(d&&!d(s.content))return{status:"invalid",message:s};const l=async s=>{await z(e.address,t.topic,i,s,n)};if(void 0===s.content)return{status:"unsupported",message:r?s:await Q(s,n)};c&&r&&await Y(r,n),a[s.contentType]&&await Promise.all(a[s.contentType].map((r=>r({client:e,conversation:t,db:n,message:s,processors:a,updateConversationMetadata:l}))));const u=await Q(s,n);!s.isSending&&m(s.sentAt,t.updatedAt)&&await G(t.topic,s.sentAt,n);return{status:"processed",message:await Z(u,{status:"processed"},n)}}finally{const e=te.indexOf(s.xmtpID);e>-1&&te.splice(e,1)}},se=async({client:e,conversation:t,db:n,message:s,namespaces:r,processors:a,validators:o,process:c=ne,decode:i=l})=>{if(void 0===s.content&&s.contentBytes&&e&&a[s.contentType]){const d=await i(s.contentBytes,e);return void 0===d.content?s:c({conversation:t,client:e,db:n,message:{...s,content:d.content,contentBytes:void 0},namespaces:r,processors:a,validators:o},!0)}return s},re=async(e,t)=>{const n=t.table("messages");return(await n.where({conversationTopic:e}).reverse().sortBy("sentAt"))[0]},ae=async(e,t,n)=>n.table("consent").where({walletAddress:e,peerAddress:t}).first(),oe=async(e,t)=>{const n=t.table("consent");return(await n.where({walletAddress:e}).toArray()).map((e=>u.fromAddress(e.peerAddress,e.state)))},ce=async(e,t)=>{const n=await oe(e,t);return n.length?Object.fromEntries(n.map((e=>[e.value,e]))):{}},ie=async(e,t,n)=>{const s=await ae(e,t,n);return s?.state??"unknown"},de=async(e,t)=>{const n=await oe(e.address,t);e.contacts.setConsentListEntries(n)},le=new h,ue=async(e,t,n,s)=>le.runExclusive((async()=>{const r=s.table("consent");await r.put({peerAddress:t,state:n,walletAddress:e})})),we=async(e,t)=>le.runExclusive((async()=>{const n=t.table("consent");await n.bulkPut(e)})),pe=e=>{const[t,s]=n(!1),[c,i]=n(null),d=r(!1),{client:l,setClient:u,codecs:p,db:y,processors:m,namespaces:v,validators:g}=a(O),f=o((async({keys:t,options:n,signer:r})=>{if(!l&&(r||t)){if(d.current)return;let a;d.current=!0,i(null),s(!0);try{a=await w.create(r??null,{...n,codecs:p,privateKeyOverride:t}),u(a)}catch(t){throw u(void 0),i(t),e?.(t),t}finally{d.current=!1}s(!1);try{await de(a,y)}catch(t){e?.(t)}try{await(async({client:e,db:t,namespaces:n,processors:s,validators:r,reprocess:a=se})=>{const o=await(async e=>{const t=e.table("messages");return await t.where({status:"unprocessed"}).toArray()})(t);await Promise.all(o.map((async o=>{const c=await R(e.address,o.conversationTopic,t);c&&await a({conversation:c,client:e,db:t,message:o,namespaces:n,processors:s,validators:r})})))})({client:a,db:y,processors:m,namespaces:v,validators:g})}catch(t){e?.(t)}return d.current=!1,a}return l}),[l,p,y,v,e,m,u,g]),h=o((async()=>{l&&(await l.close(),u(void 0))}),[l,u]);return{client:l,disconnect:h,error:c,initialize:f,isLoading:t}},ye=()=>{const e=a(O),{db:t}=e;return{clearCache:o((async()=>{await L(t)}),[t]),db:t}},me=()=>{const{client:e}=pe(),{db:t}=ye();return{saveConversation:o((n=>e?W(n,t):void 0),[e,t]),updateConversation:o((async(e,n)=>{await N(e,n,t)}),[t]),updateMetadata:o((async(n,s,r)=>{e&&await z(e.address,n,s,r,t)}),[e,t])}},ve=()=>{const{client:e}=pe(),{db:t}=ye();return{getByTopic:o((async t=>e?F(t,e):void 0),[e]),getCachedByTopic:o((async n=>e?R(e.address,n,t):void 0),[e,t]),getCachedByPeerAddress:o((async n=>e?U(e.address,n,t):void 0),[e,t]),getLastMessage:o((async e=>re(e,t)),[t]),hasConversationTopic:o((async n=>!!e&&$(e.address,n,t)),[e,t])}},ge=()=>{const e=a(O),{processors:t,namespaces:n,validators:s}=e,{client:r}=pe(),{db:c}=ye(),i=o((async(e,a)=>ne({client:r,conversation:e,db:c,message:a,namespaces:n,processors:t,validators:s})),[r,c,n,t,s]),l=o((async(e,t)=>Z(e,t,c)),[c]),u=o((async(e,t)=>(async(e,t,n)=>Z(e,{hasSendError:!1,isSending:!1,sendOptions:void 0,sentAt:t},n))(e,t,c)),[c]),w=o((async e=>J(e,c)),[c]),p=o((async e=>Y(e,c)),[c]),y=o((async(e,t,n,s)=>{if(!r)throw new Error("XMTP client is required to send a message");if(void 0===t)throw new Error("Message content is required to send a message");const{onSuccess:a,onError:o,...w}=s??{},p={...w,contentType:n??d};try{const{message:n,preparedMessage:s}=await(async({client:e,content:t,conversation:n,sendOptions:s})=>{const r=await F(n.topic,e);if(!r)throw new Error("Conversation not found in XMTP client, unable to prepare message");const a=await r.prepareMessage(t,s),o=new Date;return{message:{content:t,contentType:s?.contentType?.toString()??d.toString(),conversationTopic:n.topic,hasLoadError:!1,hasSendError:!1,isSending:!0,senderAddress:e.address,sentAt:o,status:"unprocessed",uuid:f(),walletAddress:e.address,xmtpID:await a.messageID()},preparedMessage:a}})({client:r,content:t,conversation:e,sendOptions:p}),{status:o,message:w}=await i(e,n);switch(o){case"invalid":throw new Error("Unable to send message: content is invalid");case"duplicate":throw new Error("Unable to send message: message is a duplicate")}if("processed"===o)try{const t=await s.send();return await G(e.topic,t.sent,c),a?.(t),w.id&&await u(w,t.sent),{cachedMessage:w,sentMessage:t}}catch(e){throw w.id&&await l(w,{hasSendError:!0,sendOptions:p}),e}return{cachedMessage:w}}catch(e){throw o?.(e),e}}),[r,c,i,l,u]),m=o((async e=>{if(!e.hasSendError)throw new Error("Resending a message that hasn't failed to send is not allowed");if(!r)throw new Error("XMTP client is required to send a message");const t=await F(e.conversationTopic,r);if(!t){throw new Error("Conversation not found in XMTP client, unable to send message")}const n=await t.send(e.content,e.sendOptions);return await G(t.topic,n.sent,c),await u(e,n.sent),n}),[r,c,u]);return{deleteMessage:p,getMessageByXmtpID:w,processMessage:i,resendMessage:m,sendMessage:y,updateMessage:l}},fe=e=>{const[t,s]=n(!1),[a,o]=n(!1),[i,d]=n(null),{client:l}=pe(),{processMessage:u}=ge(),{saveConversation:w}=me(),{hasConversationTopic:y}=ve(),m=(()=>{const{db:e}=ye(),{client:t}=pe();return A((async()=>t?e.table("conversations").where("walletAddress").equals(t.address).reverse().sortBy("updatedAt"):[]),[t?.address])??[]})(),v=r(!1),{onConversations:g,onError:f}=e??{};return c((()=>{if(!l){const e=new Error("XMTP client is required to fetch conversations");return d(e),void f?.(e)}(async()=>{if(!v.current){v.current=!0,s(!0),o(!1),d(null);try{const e=await l.conversations.list()??[];await Promise.all(e.map((async e=>{if(!await y(e.topic)){const t=await w(K(e,l.address)),n=await e.messages({direction:p.SORT_DIRECTION_DESCENDING,limit:1});if(n.length>0&&t){const e=n[0];await u(t,H(e,l.address))}}}))),o(!0),g?.(e)}catch(e){throw d(e),f?.(e),e}finally{s(!1),v.current=!1}}})()}),[g,f,l,w,u,y]),{conversations:m,error:i,isLoaded:a,isLoading:t}},he=e=>{const[t,s]=n(!1),[r,a]=n(null),{client:c}=pe(),{sendMessage:i}=ge(),{saveConversation:d}=me(),{conversationId:l,metadata:u,onError:w}=e??{};return{error:r,isLoading:t,startConversation:o((async(e,t,n,r)=>{if(void 0===c){const e=new Error("XMTP client is required to start a conversation");return a(e),w?.(e),{cachedConversation:void 0,cachedMessage:void 0,conversation:void 0}}s(!0),a(null);try{const s=await c.conversations.newConversation(e,l&&u?{conversationId:l,metadata:u}:void 0),a=await d(K(s,c.address));if(!a)return{cachedConversation:void 0,cachedMessage:void 0,conversation:s};if(void 0===t)return{cachedConversation:a,cachedMessage:void 0,conversation:s};const{cachedMessage:o}=await i(a,t,n,r);return{cachedConversation:a,cachedMessage:o,conversation:s}}catch(e){throw a(e),w?.(e),e}finally{s(!1)}}),[i,c,l,u,w,d])}},Ae=e=>{const[t,s]=n(null),a=r(void 0),o=r((async e=>{a.current&&(a.current=void 0),void 0!==e&&(await e).return()})),{client:i}=pe(),{saveConversation:d}=me(),{onConversation:l,onError:u}=e??{};return c((()=>{let e=a.current;const t=o.current;return(async()=>{if(!a.current){if(void 0===i){const e=new Error("XMTP client is not available");return s(e),void u?.(e)}try{if(a.current)return;a.current=i.conversations.stream(),e=a.current;for await(const t of await e)await d(K(t,i.address)),l?.(t)}catch(n){throw s(n),u?.(n),t(e),n}}})(),()=>{t(e)}}),[i,d,u,l]),{error:t}},be=e=>{const{db:t}=ye();return A((async()=>{const n=t.table("messages");return(await n.where({conversationTopic:e}).reverse().sortBy("sentAt")).filter((e=>void 0!==e.content))[0]}),[e])},Te=e=>{const[t,s]=n(!1),[r,a]=n(null),{client:c}=pe();return{error:r,isLoading:t,canMessage:o((async t=>{if(!c)throw new Error("XMTP client is required to check if an address is on the network");s(!1),a(null);try{return await c.canMessage(t)}catch(t){throw a(t),e?.(t),t}finally{s(!1)}}),[c,e]),canMessageStatic:o((async(t,n)=>{s(!1),a(null);try{return await w.canMessage(t,n)}catch(t){throw a(t),e?.(t),t}finally{s(!1)}}),[e])}},Me=(e,t)=>{const[s,a]=n(!1),[i,d]=n(!1),[l,u]=n(null),{processMessage:w}=ge(),{updateConversation:y}=me(),m=(e=>{const{db:t}=ye(),{client:n}=pe();return A((async()=>n?t.table("messages").where({conversationTopic:e,walletAddress:n.address}).sortBy("sentAt"):[]),[e])??[]})(e.topic),{client:f}=pe(),h=r(!1),{disableAutoSync:b,onError:T,onMessages:M}=t??{},E=o((async()=>{if(h.current)return;if(!f){const e=new Error("XMTP client is not available");return u(e),void T?.(e)}let t;if(h.current=!0,d(!0),a(!1),u(null),e.isReady){const n=v([e.lastSyncedAt??Date.now(),e.updatedAt]);t=g(n,10)}try{const n=await F(e.topic,f),s=new Date,r=await(n?.messages({direction:p.SORT_DIRECTION_ASCENDING,startTime:t}))??[];await Promise.all(r.map((t=>w(e,H(t,f.address))))),e.isReady||await y(e.topic,{isReady:!0}),await y(e.topic,{lastSyncedAt:s}),a(!0),M?.(r)}catch(e){throw u(e),T?.(e),e}finally{d(!1),h.current=!1}}),[f,e,T,M,w,y]);return c((()=>{E()}),[E]),c((()=>{const e=()=>{document.hidden||b||E()};return document.addEventListener("visibilitychange",e),()=>{document.removeEventListener("visibilitychange",e)}}),[E,b]),{error:l,isLoaded:s,isLoading:i,messages:m}},Ee=()=>{const{client:e}=pe(),{db:t}=ye(),n=(()=>{const{db:e}=ye(),{client:t}=pe();return A((async()=>t?ce(t.address,e):{}),[t?.address])??{}})(),s=o((async(n,s=!1)=>{if(!e)throw new Error("XMTP client is required");s||await e.contacts.allow(n),await we(n.map((t=>({peerAddress:t,state:"allowed",walletAddress:e.address}))),t)}),[e,t]),r=o((async(n,s=!1)=>{if(!e)throw new Error("XMTP client is required");s||await e.contacts.deny(n),await we(n.map((t=>({peerAddress:t,state:"denied",walletAddress:e.address}))),t)}),[e,t]);return{allow:s,consentState:o((async n=>{if(!e)throw new Error("XMTP client is required");return ie(e.address,n,t)}),[e,t]),deny:r,entries:n,isAllowed:o((async n=>{if(!e)throw new Error("XMTP client is required");return"allowed"===await ie(e.address,n,t)}),[e,t]),isDenied:o((async n=>{if(!e)throw new Error("XMTP client is required");return"denied"===await ie(e.address,n,t)}),[e,t]),loadConsentList:o((async n=>{if(!e)throw new Error("XMTP client is required");const s=await e.contacts.loadConsentList(n);return s.length>0&&await we(s.map((t=>({peerAddress:t.value,state:t.permissionType,walletAddress:e.address}))),t),s}),[e,t]),refreshConsentList:o((async()=>{if(!e)throw new Error("XMTP client is required");await t.table("consent").clear();const n=await(e?.contacts.refreshConsentList());return n.length>0&&await we(n.map((t=>({peerAddress:t.value,state:t.permissionType,walletAddress:e.address}))),t),n}),[e,t])}},Se=e=>{const[t,s]=n(!1),[r,a]=n(null),{sendMessage:c}=ge(),{allow:i,consentState:d}=Ee(),{onError:l,onSuccess:u}=e??{};return{error:r,isLoading:t,sendMessage:o((async(e,t,n,r)=>{s(!0),a(null);try{const{sentMessage:s}=await c(e,t,n,{...r,onSuccess:u,onError:l});return"allowed"!==await d(e.peerAddress)&&await i([e.peerAddress],!0),s}catch(e){throw a(e),e}finally{s(!1)}}),[c,i,d,l,u])}},De=e=>{const[t,s]=n(!1),[r,a]=n(null),{resendMessage:c,deleteMessage:i}=ge(),{onError:d,onSuccess:l}=e??{},u=o((async e=>{s(!0),a(null);try{const t=await c(e);return l?.(t),t}catch(e){throw a(e),d?.(e),e}finally{s(!1)}}),[c,d,l]);return{cancel:o((async e=>{try{await i(e)}catch(e){throw a(e),d?.(e),e}}),[i,d]),error:r,isLoading:t,resend:u}},xe=(e,t)=>{const[s,a]=n(null),o=r(void 0),i=r((async e=>{o.current&&(o.current=void 0),void 0!==e&&(await e).return(void 0)})),{processMessage:d}=ge(),{getCachedByTopic:l}=ve(),{client:u}=pe();return c((()=>{let n=o.current;const s=i.current;return(async()=>{if(!o.current){if(void 0===u){const e=new Error("XMTP client is not available");return a(e),void t?.(e)}try{if(o.current)return;o.current=u.conversations.streamAllMessages(),n=o.current;for await(const t of await n){const n=await l(t.conversation.topic);n&&await d(n,H(t,u.address)),e?.(t)}}catch(e){throw a(e),t?.(e),s(n),e}}})(),()=>{s(n)}}),[e,u,t,d,l]),{error:s}},Ie=(e,t)=>{const[s,a]=n(null),o=r(void 0),i=r((async e=>{o.current&&(o.current=void 0),void 0!==e&&(await e).return()})),{processMessage:d}=ge(),{client:l}=pe(),{onError:u,onMessage:w}=t??{};return c((()=>{if(!e||!l){const e=new Error("XMTP client and/or conversation is not available");return a(e),u?.(e),()=>{}}let t=o.current;const n=i.current;return(async()=>{if(o.current)return;const s=await F(e.topic,l);if(s)try{if(o.current)return;o.current=s.streamMessages(),t=o.current;for await(const n of await t)await d(e,H(n,l.address)),w?.(n)}catch(e){throw a(e),u?.(e),n(t),e}})(),()=>{n(t)}}),[l,e,u,w,d]),{error:s}},Ce=(e,t)=>{const{allow:s,deny:a}=Ee(),[o,i]=n(null),d=r(void 0),l=r((async e=>{d.current&&(d.current=void 0),void 0!==e&&(await e).return()})),{client:u}=pe();return c((()=>{let n=d.current;const r=l.current;return(async()=>{if(!d.current){if(void 0===u){const e=new Error("XMTP client is not available");return i(e),void t?.(e)}try{if(d.current)return;d.current=u.contacts.streamConsentList(),n=d.current;for await(const t of await n)t.allowAddress&&s(t.allowAddress.walletAddresses,!0),t.denyAddress&&a(t.denyAddress.walletAddresses,!0),e?.(t)}catch(e){throw i(e),t?.(e),r(n),e}}})(),()=>{r(n)}}),[u,t,e,s,a]),{error:o}},Xe="attachment",Pe=e=>{switch(e.contentType){case M.toString():case E.toString():return e.content;default:return}},Le=S.object({filename:S.string(),mimeType:S.string(),data:S.instanceof(Uint8Array)}),qe=S.object({url:S.string(),contentDigest:S.string(),salt:S.instanceof(Uint8Array),nonce:S.instanceof(Uint8Array),secret:S.instanceof(Uint8Array),scheme:S.string(),contentLength:S.number().gte(0),filename:S.string()}),Be={codecs:[new b,new T],contentTypes:[M.toString(),E.toString()],namespace:Xe,validators:{[M.toString()]:e=>{const{success:t}=Le.safeParse(e);return t},[E.toString()]:e=>{const{success:t}=qe.safeParse(e);return t}}},Oe=10485760,_e=(e,t)=>{const{client:a}=pe(),{db:i}=ye(),{updateMessage:d}=ge(),[l,u]=n(void 0),[w,p]=n("init"),[y,m]=n(void 0),v=r(!1),{disableAutoload:g=!1,autoloadMaxFileSize:f=Oe}=t??{},h=s((()=>(e=>{if(e.contentType===E.toString()){const t=e.metadata?.[Xe];return t}})(e)),[e]),A=o((async(t=!1)=>{if(h&&"loaded"!==w)return m(h),void p("loaded");if(a&&e.contentType===E.toString()&&!h&&"loading"!==w&&"loaded"!==w&&!y&&(e.hasLoadError&&t||!e.hasLoadError))try{p("loading");const t=await T.load(e.content,a);try{await(async(e,t,n)=>{e.contentType===E.toString()&&await ee(e,Xe,t,n)})(e,t,i)}catch{}m(t),p("loaded")}catch(t){await d(e,{hasLoadError:!0}),u(new Error("Unable to load remote attachment")),p("error")}else u(new Error("XMTP client is required to load remote attachments")),p("error")}),[h,w,a,e,y,i,d]),b=o((()=>{A(!0)}),[A]);return c((()=>{(async()=>{if(!v.current&&(v.current=!0,!y&&"loading"!==w&&"loaded"!==w))switch(e.contentType){case M.toString():m(e.content),p("loaded"),v.current=!1;break;case E.toString():if(h)return m(h),p("loaded"),void(v.current=!1);if(e.content.contentLength>f)return p("autoloadMaxFileSizeExceeded"),void(v.current=!1);g||await A(),v.current=!1;break;default:u(new Error("Message is not an attachment content type")),p("error"),v.current=!1}})()}),[h,f,i,g,A,e,y,w]),{attachment:y,error:l,load:b,status:w}},je=e=>{const{db:t}=ye();return A((async()=>{if(!e)return[];try{const n=t.table("reactions");return await n.where("referenceXmtpID").equals(e.xmtpID).sortBy("sentAt")}catch{return[]}}),[e])??[]},ke="reactions",Re=async(e,t)=>{const n=t.table("reactions"),s={content:e.content,referenceXmtpID:e.referenceXmtpID,schema:e.schema,senderAddress:e.senderAddress},r=await n.where(s).first();return r||void 0},Ue=async(e,t)=>t.table("reactions").where({referenceXmtpID:e}).sortBy("sentAt"),Fe=e=>!!e?.metadata?.[ke],Ne=S.object({reference:S.string(),action:S.enum(["added","removed"]),content:S.string(),schema:S.enum(["unicode","shortcode","custom"])}),ze=e=>{const{success:t}=Ne.safeParse(e);return t},Ge=new h,$e={codecs:[new D],contentTypes:[x.toString()],namespace:ke,processors:{[x.toString()]:[async({message:e,db:t})=>{await Ge.runExclusive((async()=>{const n=y.fromString(e.contentType);if(x.sameAs(n)&&ze(e.content)){const n=e.content,s={content:n.content,referenceXmtpID:n.reference,schema:n.schema,senderAddress:e.senderAddress,sentAt:e.sentAt,xmtpID:e.xmtpID};switch(n.action){case"added":await(async(e,t)=>{const n=t.table("reactions"),s=await Re(e,t);return s?(await n.update(s.id,{sentAt:e.sentAt}),s.id):n.add(e)})(s,t);break;case"removed":await(async(e,t)=>{const n=t.table("reactions"),s=await Re(e,t);s&&await n.delete(s.id)})(s,t)}await(async(e,t)=>{const n=await Ue(e,t),s=await J(e,t);s&&await ee(s,ke,n.length>0,t)})(n.reference,t)}}))}]},schema:{reactions:"\n ++id,\n [content+referenceXmtpID+schema+senderAddress],\n referenceXmtpID,\n content,\n schema,\n senderAddress,\n sentAt,\n xmtpID\n "},validators:{[x.toString()]:ze}},Ke=async(e,t)=>{const n=t.table("replies"),s=await n.where({referenceXmtpID:e.xmtpID}).toArray();if(s.length>0){const e=t.table("messages");return await e.where("xmtpID").anyOf(s.map((e=>e.xmtpID))).sortBy("sentAt")}return[]},Ve=async(e,t)=>{const n=t.table("replies");return(await n.where({referenceXmtpID:e.xmtpID}).toArray()).length>0},We=async(e,t)=>{if(C.sameAs(y.fromString(e.contentType))&&"processed"===e.status&&e.content){const n=e.content;return J(n.reference,t)}},He=S.object({content:S.any(),contentType:S.object({authorityId:S.string(),typeId:S.string(),versionMajor:S.number().gt(0),versionMinor:S.number().gte(0)}),reference:S.string()}),Je=e=>{const{success:t}=He.safeParse(e);return t},Qe={codecs:[new I],contentTypes:[C.toString()],namespace:"replies",processors:{[C.toString()]:[async({message:e,db:t})=>{const n=y.fromString(e.contentType);if(C.sameAs(n)&&Je(e.content)){const n=e.content;await(async(e,t,n)=>{const s=n.table("replies"),r=await s.where({referenceXmtpID:e,xmtpID:t}).first();return r?r.id:s.add({referenceXmtpID:e,xmtpID:t})})(n.reference,e.xmtpID,t)}}]},schema:{replies:"\n ++id,\n [referenceXmtpID+xmtpID],\n referenceXmtpID,\n xmtpID\n "},validators:{[C.toString()]:Je}},Ye=e=>{const{db:t}=ye(),[s,r]=n(void 0);return c((()=>{(async()=>{if(e){const n=await We(e,t);n&&r(n)}})()}),[t,e]),{originalMessage:s}},Ze=e=>{const{db:t}=ye();return A((async()=>{if(!e)return[];try{return await Ke(e,t)}catch{return[]}}),[e])??[]};export{_ as XMTPProvider,Be as attachmentContentTypeConfig,we as bulkPutConsentState,L as clearCache,Y as deleteMessage,Pe as getAttachment,oe as getCachedConsentEntries,ce as getCachedConsentEntriesMap,ae as getCachedConsentEntry,ie as getCachedConsentState,U as getCachedConversationByPeerAddress,R as getCachedConversationByTopic,F as getConversationByTopic,P as getDbInstance,re as getLastMessage,J as getMessageByXmtpID,We as getOriginalMessageFromReply,Ue as getReactionsByXmtpID,Ke as getReplies,$ as hasConversationTopic,Fe as hasReaction,Ve as hasReply,j as isValidAddress,de as loadConsentListFromCache,ue as putConsentState,$e as reactionContentTypeConfig,Qe as replyContentTypeConfig,W as saveConversation,Q as saveMessage,G as setConversationUpdatedAt,X as textContentTypeConfig,K as toCachedConversation,H as toCachedMessage,N as updateConversation,z as updateConversationMetadata,Z as updateMessage,ee as updateMessageMetadata,_e as useAttachment,Te as useCanMessage,pe as useClient,Ee as useConsent,ve as useConversation,fe as useConversations,ye as useDb,be as useLastMessage,ge as useMessage,Me as useMessages,je as useReactions,Ze as useReplies,Ye as useReply,De as useResendMessage,Se as useSendMessage,he as useStartConversation,xe as useStreamAllMessages,Ce as useStreamConsentList,Ae as useStreamConversations,Ie as useStreamMessages};
//# sourceMappingURL=index.js.map
{
"name": "@xmtp/react-sdk",
"version": "6.0.0",
"version": "6.0.1",
"description": "XMTP client SDK for React apps written in TypeScript",

@@ -5,0 +5,0 @@ "keywords": [

@@ -24,13 +24,22 @@ # React XMTP client SDK

The XMTP React SDK requires React, the XMTP JS SDK, and several content types.
**NPM**
```bash
# npm
npm install @xmtp/react-sdk
npm install react @xmtp/react-sdk @xmtp/xmtp-js @xmtp/content-type-reaction @xmtp/content-type-remote-attachment @xmtp/content-type-reply
```
# pnpm
pnpm install @xmtp/react-sdk
**PNPM**
# yarn
yarn add @xmtp/react-sdk
```bash
pnpm install react @xmtp/react-sdk @xmtp/xmtp-js @xmtp/content-type-reaction @xmtp/content-type-remote-attachment @xmtp/content-type-reply
```
**Yarn**
```bash
yarn add react @xmtp/react-sdk @xmtp/xmtp-js @xmtp/content-type-reaction @xmtp/content-type-remote-attachment @xmtp/content-type-reply
```
### Buffer polyfill

@@ -37,0 +46,0 @@

@@ -31,4 +31,4 @@ import { useCallback, useContext } from "react";

/**
* This hook is for internal use only and wraps helper functions to include
* the client, DB instance, and other values for easier consumption.
* This hook wraps helper functions to include the client, DB instance, and
* other values for easier consumption.
*/

@@ -35,0 +35,0 @@ export const useMessage = () => {

@@ -37,2 +37,3 @@ // context

export { useCanMessage } from "./hooks/useCanMessage";
export { useMessage } from "./hooks/useMessage";
export { useMessages } from "./hooks/useMessages";

@@ -39,0 +40,0 @@ export { useSendMessage } from "./hooks/useSendMessage";