diff --git a/src/lib/Client.ts b/src/lib/Client.ts index 0f338ff0f..d4a7d9e2f 100644 --- a/src/lib/Client.ts +++ b/src/lib/Client.ts @@ -18,6 +18,15 @@ export class Client { conversations: Conversations; contacts: Contacts; + /** + * Creates a new instance of the Client class using the provided signer. + * + * @param {Signer} signer - The signer object used for authentication and message signing. + * @param {Partial} opts - Optional configuration options for the Client. + * @returns {Promise} A Promise that resolves to a new Client instance. + * + * See {@link https://xmtp.org/docs/build/authentication#create-a-client | XMTP Docs} for more information. + */ static async create( signer: Signer, opts?: Partial, @@ -57,6 +66,12 @@ export class Client { }); } +/** + * Creates a new instance of the XMTP Client with a randomly generated address. + * + * @param {Partial} opts - Optional configuration options for the Client. + * @returns {Promise} A Promise that resolves to a new Client instance with a random address. + */ static async createRandom(opts?: Partial): Promise { const options = defaultOptions(opts); const address = await XMTPModule.createRandom( @@ -66,6 +81,16 @@ export class Client { return new Client(address); } +/** + * Creates a new instance of the Client class from a provided key bundle. + * + * This method is useful for scenarios where you want to manually handle private key storage, + * allowing the application to have access to XMTP keys without exposing wallet keys. + * + * @param {string} keyBundle - The key bundle used for address generation. + * @param {Partial} opts - Optional configuration options for the Client. + * @returns {Promise} A Promise that resolves to a new Client instance based on the provided key bundle. + */ static async createFromKeyBundle( keyBundle: string, opts?: Partial, @@ -79,6 +104,16 @@ export class Client { return new Client(address); } + /** + * Determines whether the current user can send messages to a specified peer. + * + * This method checks if the specified peer has signed up for XMTP + * and ensures that the message is not addressed to the sender (no self-messaging). + * + * @param {string} peerAddress - The address of the peer to check for messaging eligibility. + * @returns {Promise} A Promise resolving to true if messaging is allowed, and false otherwise. + */ + async canMessage(peerAddress: string): Promise { return await XMTPModule.canMessage(this.address, peerAddress); } @@ -89,6 +124,14 @@ export class Client { this.contacts = new Contacts(this); } + /** + * Exports the key bundle associated with the current XMTP address. + * + * This method allows you to obtain the unencrypted key bundle for the current XMTP address. + * Ensure the exported keys are stored securely and encrypted. + * + * @returns {Promise} A Promise that resolves to the unencrypted key bundle for the current XMTP address. + */ async exportKeyBundle(): Promise { return XMTPModule.exportKeyBundle(this.address); } @@ -97,6 +140,16 @@ export class Client { // async importConversation(exported: string): Promise { ... } // async exportConversation(topic: string): Promise { ... } +/** + * Retrieves a list of batch messages based on the provided queries. + * + * This method pulls messages associated from multiple conversation with the current address + * and specified queries. + * + * @param {Query[]} queries - An array of queries to filter the batch messages. + * @returns {Promise} A Promise that resolves to a list of batch messages. + * @throws {Error} The error is logged, and the method gracefully returns an empty array. + */ async listBatchMessages(queries: Query[]): Promise { try { return await XMTPModule.listBatchMessages(this.address, queries); @@ -106,6 +159,15 @@ export class Client { } } + /** + * Encrypts a local attachment for secure transmission. + * + * This asynchronous method takes a file, checks if it's a local file URI, + * and encrypts the attachment for secure transmission. + * @param {DecryptedLocalAttachment} file - The local attachment to be encrypted. + * @returns {Promise} A Promise that resolves to the encrypted local attachment. + * @throws {Error} Throws an error if the attachment is not a local file URI (must start with "file://"). + */ async encryptAttachment( file: DecryptedLocalAttachment, ): Promise { @@ -114,6 +176,15 @@ export class Client { } return await XMTPModule.encryptAttachment(this.address, file); } + + /** + * Decrypts an encrypted local attachment. + * + * This asynchronous method takes an encrypted local attachment and decrypts it. + * @param {EncryptedLocalAttachment} encryptedFile - The encrypted local attachment to be decrypted. + * @returns {Promise} A Promise that resolves to the decrypted local attachment. + * @throws {Error} Throws an error if the attachment is not a local file URI (must start with "file://"). + */ async decryptAttachment( encryptedFile: EncryptedLocalAttachment, ): Promise { @@ -123,6 +194,13 @@ export class Client { return await XMTPModule.decryptAttachment(this.address, encryptedFile); } +/** + * Sends a prepared message. + * + * @param {PreparedLocalMessage} prepared - The prepared local message to be sent. + * @returns {Promise} A Promise that resolves to a string identifier for the sent message. + * @throws {Error} Throws an error if there is an issue with sending the prepared message. + */ async sendPreparedMessage(prepared: PreparedLocalMessage): Promise { try { return await XMTPModule.sendPreparedMessage(this.address, prepared); diff --git a/src/lib/Conversation.ts b/src/lib/Conversation.ts index 0f3df09fd..f5ef5489b 100644 --- a/src/lib/Conversation.ts +++ b/src/lib/Conversation.ts @@ -36,7 +36,18 @@ export class Conversation { ); } - // TODO: Support pagination and conversation ID here +/** + * Lists messages in a conversation with optional filters. + * + * @param {number} limit - Optional limit to the number of messages to return. + * @param {number | Date} before - Optional timestamp to filter messages before. + * @param {number | Date} after - Optional timestamp to filter messages after. + * @param {"SORT_DIRECTION_ASCENDING" | "SORT_DIRECTION_DESCENDING"} direction - Optional sorting direction for messages. + * @returns {Promise} A Promise that resolves to an array of decoded messages. + * @throws {Error} Throws an error if there is an issue with listing messages. + * + * @todo Support pagination and conversation ID in future implementations. + */ async messages( limit?: number | undefined, before?: number | Date | undefined, @@ -58,7 +69,15 @@ export class Conversation { } } - // TODO: support conversation ID + /** + * Sends a message to the current conversation. + * + * @param {string | MessageContent} content - The content of the message. It can be either a string or a structured MessageContent object. + * @returns {Promise} A Promise that resolves to a string identifier for the sent message. + * @throws {Error} Throws an error if there is an issue with sending the message. + * + * @todo Support specifying a conversation ID in future implementations. + */ async send(content: string | MessageContent): Promise { try { if (typeof content === "string") { @@ -71,15 +90,21 @@ export class Conversation { } } - // Prepare the message to be sent. - // - // Instead of immediately `.send`ing a message, you can `.prepare` it first. - // This yields a `PreparedLocalMessage` object, which you can send later. - // This is useful to help construct a robust pending-message queue - // that can survive connectivity outages and app restarts. - // - // Note: the sendPreparedMessage() method is available on both this `Conversation` - // or the top-level `Client` (when you don't have the `Conversation` handy). + /** + * Prepares a message to be sent, yielding a `PreparedLocalMessage` object. + * + * Instead of immediately sending a message, you can prepare it first using this method. + * This yields a `PreparedLocalMessage` object, which you can send later. + * This is useful to help construct a robust pending-message queue + * that can survive connectivity outages and app restarts. + * + * Note: the {@linkcode Conversation.sendPreparedMessage | sendPreparedMessage} method is available on both this {@linkcode Conversation} + * or the top-level `Client` (when you don't have the `Conversation` handy). + * + * @param {string | MessageContent} content - The content of the message. It can be either a string or a structured MessageContent object. + * @returns {Promise} A Promise that resolves to a `PreparedLocalMessage` object. + * @throws {Error} Throws an error if there is an issue with preparing the message. + */ async prepareMessage(content: string | MessageContent): Promise { try { if (typeof content === "string") { @@ -92,6 +117,16 @@ export class Conversation { } } + /** + * Sends a prepared local message. + * + * This asynchronous method takes a `PreparedLocalMessage` and sends it. + * Prepared messages are created using the {@linkcode Conversation.prepareMessage | prepareMessage} method. + * + * @param {PreparedLocalMessage} prepared - The prepared local message to be sent. + * @returns {Promise} A Promise that resolves to a string identifier for the sent message. + * @throws {Error} Throws an error if there is an issue with sending the prepared message. + */ async sendPreparedMessage(prepared: PreparedLocalMessage): Promise { try { return await XMTP.sendPreparedMessage(this.clientAddress, prepared); @@ -101,6 +136,16 @@ export class Conversation { } } + /** + * Decodes an encrypted message, yielding a `DecodedMessage` object. + * + * This asynchronous method takes an encrypted message and decodes it. + * The result is a `DecodedMessage` object containing the decoded content and metadata. + * + * @param {string} encryptedMessage - The encrypted message to be decoded. + * @returns {Promise} A Promise that resolves to a `DecodedMessage` object. + * @throws {Error} Throws an error if there is an issue with decoding the message. + */ async decodeMessage(encryptedMessage: string): Promise { try { return await XMTP.decodeMessage( @@ -114,10 +159,28 @@ export class Conversation { } } + /** + * Retrieves the consent state for the current conversation. + * + * This asynchronous method determine the consent state + * for the current conversation, indicating whether the user has allowed, denied, + * or is yet to provide consent. + * + * @returns {Promise<"allowed" | "denied" | "unknown">} A Promise that resolves to the consent state, which can be "allowed," "denied," or "unknown." + */ async consentState(): Promise<"allowed" | "denied" | "unknown"> { return await XMTP.conversationConsentState(this.clientAddress, this.topic); } - + /** + * Sets up a real-time message stream for the current conversation. + * + * This method subscribes to incoming messages in real-time and listens for new message events. + * When a new message is detected, the provided callback function is invoked with the details of the message. + * Additionally, this method returns a function that can be called to unsubscribe and end the message stream. + * + * @param {Function} callback - A callback function that will be invoked with the new DecodedMessage when a message is received. + * @returns {Function} A function that, when called, unsubscribes from the message stream and ends real-time updates. + */ streamMessages( callback: (message: DecodedMessage) => Promise, ): () => void { diff --git a/src/lib/Conversations.ts b/src/lib/Conversations.ts index ce99fb821..3d2e5c298 100644 --- a/src/lib/Conversations.ts +++ b/src/lib/Conversations.ts @@ -11,6 +11,11 @@ export default class Conversations { this.client = client; } + /** + * This method returns a list of all conversations that the client is a member of. + * + * @returns {Promise} A Promise that resolves to an array of Conversation objects. + */ async list(): Promise { const result = await XMTPModule.listConversations(this.client.address); @@ -29,7 +34,15 @@ export default class Conversations { this.known[conversation.topic] = true; return conversation; } - +/** + * Creates a new conversation. + * + * This method creates a new conversation with the specified peer address and context. + * + * @param {string} peerAddress - The address of the peer to create a conversation with. + * @param {ConversationContext} context - Optional context to associate with the conversation. + * @returns {Promise} A Promise that resolves to a Conversation object. + */ async newConversation( peerAddress: string, context?: ConversationContext, @@ -41,7 +54,16 @@ export default class Conversations { ); } - async stream(callback: (conversation: Conversation) => Promise) { + /** + * Sets up a real-time stream to listen for new conversations being started. + * + * This method subscribes to conversations in real-time and listens for incoming conversation events. + * When a new conversation is detected, the provided callback function is invoked with the details of the conversation. + * @param {Function} callback - A callback function that will be invoked with the new Conversation when a conversation is started. + * @returns {Promise} A Promise that resolves when the stream is set up. + * @warning This stream will continue infinitely. To end the stream, you can call {@linkcode Conversations.cancelStream | cancelStream()}. + */ + async stream(callback: (conversation: Conversation) => Promise): Promise { XMTPModule.subscribeToConversations(this.client.address); XMTPModule.emitter.addListener( "conversation", @@ -65,9 +87,16 @@ export default class Conversations { ); } +/** + * Listen for new messages in all conversations. + * + * This method subscribes to all conversations in real-time and listens for incoming and outgoing messages. + * @param {Function} callback - A callback function that will be invoked when a message is sent or received. + * @returns {Promise} A Promise that resolves when the stream is set up. + */ async streamAllMessages( callback: (message: DecodedMessage) => Promise, - ) { + ): Promise { XMTPModule.subscribeToAllMessages(this.client.address); XMTPModule.emitter.addListener( "message", @@ -91,10 +120,16 @@ export default class Conversations { ); } + /** + * Cancels the stream for new conversations. + */ cancelStream() { XMTPModule.unsubscribeFromConversations(this.client.address); } + /** + * Cancels the stream for new messages in all conversations. + */ cancelStreamAllMessages() { XMTPModule.unsubscribeFromAllMessages(this.client.address); }