Storage

Uploading and Downloading Assets

Umi enables us to upload and download any file via the UploaderInterface and DownloaderInterface interfaces respectively.

Generic files

Because the definition of a file varies between libraries and whether we are in the browser or a Node server, Umi defines a type called GenericFile so we can agree on a common type for files.

type GenericFile = {
  readonly buffer: Uint8Array;
  readonly fileName: string;
  readonly displayName: string;
  readonly uniqueName: string;
  readonly contentType: string | null;
  readonly extension: string | null;
  readonly tags: GenericFileTag[];
};

As you can see, its content is stored as a Uint8Array buffer and it includes some metadata such as its filename, its display name, its content type, etc. It also includes a simple key-value storage to store any additional data as tags. These can also be used to pass additional information about the file to the uploader.

You can use the createGenericFile helper function to create a new GenericFile instance from its content and filename. This function also accepts a contentType that you should set as the MIME Type of your file to help browsers to render your file correctly.

To help us convert a file from a specific environment to and from a GenericFile, Umi also provides some additional helper methods.

// Create a generic file directly.
createGenericFile('some content', 'my-file.txt', { contentType: "text/plain" });

// Parse a generic file to and from a browser file.
await createGenericFileFromBrowserFile(myBrowserFile);
createBrowserFileFromGenericFile(myGenericFile);

// Parse a generic file to and from a JSON object.
createGenericFileFromJson(myJson);
parseJsonFromGenericFile(myGenericFile);

The uploader interface

First and foremost, the UploaderInterface provides an upload method that can be used to upload one or several files at once. It returns an array of URIs that represent the uploaded files in the order in which they were passed.

const [myUri, myOtherUri] = await umi.uploader.upload([myFile, myOtherFile]);

The upload method also accepts some options to configure the upload process such as an abort signal to cancel the upload or an onProgress callback to track the upload progress. Note that these may not be supported by all uploaders.

const myUris = await umi.uploader.upload(myFiles, {
  signal: myAbortSignal,
  onProgress: (percent) => {
    console.log(`${percent * 100}% uploaded...`);
  },
})

The UploaderInterface also provides a uploadJson method that converts a JSON object into a file and uploads it.

const myUri = await umi.uploader.uploadJson({ name: 'John', age: 42 });

Finally, if an uploader charges an amount to store a set of files, you may find out how much it will cost by using the getUploadPrice method. It will return a custom Amount object which can be in any currency and unit.

const price = await umi.uploader.getUploadPrice(myFiles);

The downloader interface

Reciprocally, the DownloaderInterface provides a download method that can be used to download one or several files at once and a downloadJson method that can be used to download a parsed JSON file. Both of these methods can be cancelled via an abort signal.

// Download one or several files.
const [myFile, myOtherFile] = await umi.downloader.download([myUri, myOtherUri]);

// Download using an abort signal.
const myFiles = await umi.downloader.download(myUris, { signal: myAbortSignal });

// Download a JSON file.
type Person = { name: string; age: number; };
const myJsonObject = await umi.downloader.downloadJson<Person>(myUri);

The mock storage

Umi provides a mock storage helper class that acts as both an uploader and a downloader. It can be used to test your application without having to set up a real storage service. Anything that is uploaded to the mock storage will be cached in memory such that it can be downloaded later on.

The mock storage helper is available as a standalone package and must be installed separately.

npm install @metaplex-foundation/umi-storage-mock

Then, we can register the plugin it provides to our Umi instance and start using it.

import { mockStorage } from '@metaplex-foundation/umi-storage-mock';

umi.use(mockStorage());
const [myUri] = await umi.uploader.upload([myFile]);
const [myDownloadedFile] = await umi.downloader.download([myUri]);
// myFile and myDownloadedFile are identical.

Last updated