Skip to content

Commit

Permalink
Merge pull request #152 from xmtp/kele/code-comment-documentation
Browse files Browse the repository at this point in the history
In line code comment documentation
  • Loading branch information
kele-leanes authored Nov 29, 2023
2 parents 22b79fa + b1a4fe1 commit 3a4f98d
Show file tree
Hide file tree
Showing 3 changed files with 191 additions and 15 deletions.
78 changes: 78 additions & 0 deletions src/lib/Client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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<ClientOptions>} opts - Optional configuration options for the Client.
* @returns {Promise<Client>} 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<ClientOptions>,
Expand Down Expand Up @@ -57,6 +66,12 @@ export class Client {
});
}

/**
* Creates a new instance of the XMTP Client with a randomly generated address.
*
* @param {Partial<ClientOptions>} opts - Optional configuration options for the Client.
* @returns {Promise<Client>} A Promise that resolves to a new Client instance with a random address.
*/
static async createRandom(opts?: Partial<ClientOptions>): Promise<Client> {
const options = defaultOptions(opts);
const address = await XMTPModule.createRandom(
Expand All @@ -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<ClientOptions>} opts - Optional configuration options for the Client.
* @returns {Promise<Client>} A Promise that resolves to a new Client instance based on the provided key bundle.
*/
static async createFromKeyBundle(
keyBundle: string,
opts?: Partial<ClientOptions>,
Expand All @@ -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<boolean>} A Promise resolving to true if messaging is allowed, and false otherwise.
*/

async canMessage(peerAddress: string): Promise<boolean> {
return await XMTPModule.canMessage(this.address, peerAddress);
}
Expand All @@ -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<string>} A Promise that resolves to the unencrypted key bundle for the current XMTP address.
*/
async exportKeyBundle(): Promise<string> {
return XMTPModule.exportKeyBundle(this.address);
}
Expand All @@ -97,6 +140,16 @@ export class Client {
// async importConversation(exported: string): Promise<Conversation> { ... }
// async exportConversation(topic: string): Promise<string> { ... }

/**
* 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<DecodedMessage[]>} 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<DecodedMessage[]> {
try {
return await XMTPModule.listBatchMessages(this.address, queries);
Expand All @@ -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<EncryptedLocalAttachment>} 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<EncryptedLocalAttachment> {
Expand All @@ -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<DecryptedLocalAttachment>} 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<DecryptedLocalAttachment> {
Expand All @@ -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<string>} 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<string> {
try {
return await XMTPModule.sendPreparedMessage(this.address, prepared);
Expand Down
87 changes: 75 additions & 12 deletions src/lib/Conversation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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<DecodedMessage[]>} 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,
Expand All @@ -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<string>} 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<string> {
try {
if (typeof content === "string") {
Expand All @@ -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<PreparedLocalMessage>} 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<PreparedLocalMessage> {
try {
if (typeof content === "string") {
Expand All @@ -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<string>} 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<string> {
try {
return await XMTP.sendPreparedMessage(this.clientAddress, prepared);
Expand All @@ -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<DecodedMessage>} 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<DecodedMessage> {
try {
return await XMTP.decodeMessage(
Expand All @@ -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>,
): () => void {
Expand Down
41 changes: 38 additions & 3 deletions src/lib/Conversations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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<Conversation[]>} A Promise that resolves to an array of Conversation objects.
*/
async list(): Promise<Conversation[]> {
const result = await XMTPModule.listConversations(this.client.address);

Expand All @@ -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<Conversation>} A Promise that resolves to a Conversation object.
*/
async newConversation(
peerAddress: string,
context?: ConversationContext,
Expand All @@ -41,7 +54,16 @@ export default class Conversations {
);
}

async stream(callback: (conversation: Conversation) => Promise<void>) {
/**
* 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<void>} 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<void>): Promise<void> {
XMTPModule.subscribeToConversations(this.client.address);
XMTPModule.emitter.addListener(
"conversation",
Expand All @@ -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<void>} A Promise that resolves when the stream is set up.
*/
async streamAllMessages(
callback: (message: DecodedMessage) => Promise<void>,
) {
): Promise<void> {
XMTPModule.subscribeToAllMessages(this.client.address);
XMTPModule.emitter.addListener(
"message",
Expand All @@ -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);
}
Expand Down

0 comments on commit 3a4f98d

Please sign in to comment.