Support attachments with your agent built with XMTP
Use the remote attachment content type (RemoteAttachmentCodec) and a storage provider to send one remote attachment of any size.
The remote attachment content type is built into the Agent SDK. No installation is required.
Send a remote attachment
Load the file. This example uses a web browser to load the file:
//image is the uploaded event.target.files[0];
const data = await new Promise((resolve, reject) => {
const reader = new FileReader();
reader.onload = () => {
if (reader.result instanceof ArrayBuffer) {
resolve(reader.result);
} else {
reject(new Error('Not an ArrayBuffer'));
}
};
reader.readAsArrayBuffer(image);
});Create an attachment object:
// Local file details
const attachment = {
filename: image?.name,
mimeType: image?.type,
data: new Uint8Array(data),
};Use encryptAttachment to encrypt an attachment:
import { encryptAttachment } from '@xmtp/agent-sdk';
const encryptedAttachment = await encryptAttachment(attachment);Upload an encrypted attachment to a location where it will be accessible via an HTTPS GET request. This location will depend on which storage provider you use based on your needs.
Now that you have a url, you can create a RemoteAttachment:
import type { RemoteAttachment } from '@xmtp/agent-sdk';
const remoteAttachment: RemoteAttachment = {
url: url,
contentDigest: encryptedAttachment.contentDigest,
salt: encryptedAttachment.salt,
nonce: encryptedAttachment.nonce,
secret: encryptedAttachment.secret,
scheme: 'https://',
filename: encryptedAttachment.filename,
contentLength: encryptedAttachment.contentLength,
};Now that you have a remote attachment, you can send it:
await ctx.conversation.sendRemoteAttachment(remoteAttachment);Receive, decode, and decrypt a remote attachment
Now that you can send a remote attachment, you need a way to receive it. For example:
import { decryptAttachment } from '@xmtp/agent-sdk';
import type { RemoteAttachment } from '@xmtp/agent-sdk';
if (ctx.isRemoteAttachment()) {
const remoteAttachment: RemoteAttachment = ctx.message.content;
// Download encrypted bytes from remoteAttachment.url
const encryptedBytes = await fetch(remoteAttachment.url).then(r => r.arrayBuffer());
const attachment = await decryptAttachment(
new Uint8Array(encryptedBytes),
remoteAttachment
);
}You now have the original attachment:
attachment.filename; // => "screenshot.png"
attachment.mimeType; // => "image/png",
attachment.data; // => [the PNG data]Once you've created the attachment object, you can create a preview to show in the message input field before sending:
const objectURL = URL.createObjectURL(
new Blob([Buffer.from(attachment.data)], {
type: attachment.mimeType,
})
);
const img = document.createElement('img');
img.src = objectURL;
img.title = attachment.filename;
