Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

In line code comment documentation #152

Merged
merged 3 commits into from
Nov 29, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading