Remote Attachment Content Type
Remote attachments of any size can be sent using the RemoteAttachmentCodec
and a storage provider.
You are welcome to provide feedback on this implementation by commenting on the Remote Attachment Content Type XIP (XMTP Improvement Proposal).
To learn how to use the remote attachment content type with the React SDK, see Handle content types with the React SDK.
Install the package
- JavaScript
npm i @xmtp/content-type-remote-attachment
Import and register
- JavaScript
// Import the codecs we're going to use
import {
AttachmentCodec,
RemoteAttachmentCodec,
} from "@xmtp/content-type-remote-attachment";
// Create the XMTP client
const xmtp = await Client.create(signer, { env: "dev" });
// Register the codecs. AttachmentCodec is for local attachments (<1MB)
xmtp.registerCodec(new AttachmentCodec());
//RemoteAttachmentCodec is for remote attachments (>1MB) using thirdweb storage
xmtp.registerCodec(new RemoteAttachmentCodec());
Create an attachment object
- JavaScript
// Local file details
const attachment = {
filename: filename,
mimeType: extname,
data: new Uint8Array(data),
};
Encrypt the attachment
Use the RemoteAttachmentCodec.encodeEncrypted
to encrypt the attachment:
- JavaScript
const encryptedEncoded = await RemoteAttachmentCodec.encodeEncrypted(
attachment,
new AttachmentCodec(),
);
Upload the encrypted attachment
Upload the encrypted attachment anywhere where it will be accessible via an HTTPS GET request. For example, you can use web3.storage:
- Web3 Storage
- Thirdweb
const { Web3Storage } = require("web3.storage");
class Upload {
constructor(name, data) {
this.name = name;
this.data = data;
}
stream() {
const self = this;
return new ReadableStream({
start(controller) {
controller.enqueue(Buffer.from(self.data));
controller.close();
},
});
}
}
const upload = new Upload("uploadIdOfYourChoice", encryptedEncoded.payload);
const web3Storage = new Web3Storage({
token: "YOURTOKENHERE",
});
const cid = await web3Storage.put([upload]);
const url = `https://${cid}.ipfs.w3s.link/uploadIdOfYourChoice`;
import { useStorageUpload } from "@thirdweb-dev/react";
const { mutateAsync: upload } = useStorageUpload();
const uploadUrl = await upload({
//encryptedEncoded.payload.buffer is a Uint8Array
//We need to convert it to a File to upload it to the IPFS network
data: [new File([encryptedEncoded.payload.buffer], file.name)], // Convert Uint8Array back to File
options: { uploadWithGatewayUrl: true, uploadWithoutDirectory: true },
});
const url = uploadUrl[0];
Create a remote attachment
Now that you have a url
, you can create a RemoteAttachment
.
- JavaScript
const remoteAttachment = {
url: url,
contentDigest: encryptedEncoded.digest,
salt: encryptedEncoded.salt,
nonce: encryptedEncoded.nonce,
secret: encryptedEncoded.secret,
scheme: "https://",
filename: attachment.filename,
contentLength: attachment.data.byteLength,
};
Send a remote attachment
Now that you have a remote attachment, you can send it:
- JavaScript
await conversation.send(remoteAttachment, {
contentType: ContentTypeRemoteAttachment,
});
Download, decrypt, and decode the attachment
Now that you can receive a remote attachment, you need a way to receive a remote attachment. For example:
- JavaScript
if (message.contentType.sameAs(RemoteAttachmentContentType)) {
const attachment = await RemoteAttachmentCodec.load(message.content, client);
}
- You now have the original attachment:
attachment.filename // => "screenshot.png"
attachment.mimeType // => "image/png",
attachment.data // => [the PNG data]
Create a preview attachment object
Once you have the attachment object created, you can also create a preview for what to show in a message input before sending:
- JavaScript
URL.createObjectURL(
new Blob([Buffer.from(attachment.data)], {
type: attachment.mimeType,
}),
),