Downloading
Downloading files stored on UHRP servers
StorageDownloader is a utility in the @bsv/sdk that allows you to download files from a Babbage storage server using a unique content address (a UHRP URL). UHRP stands for Universal Hash Resolution Protocol – it means each file is identified by the hash of its content, making the URL content-addressed and self-authenticating. In practice, this lets anyone with the UHRP URL retrieve the file and verify its integrity. Multiple storage servers (hosts) can advertise and serve the same file, so your content remains available even if one host goes offline. This guide will walk you through using StorageDownloader to fetch a file given its UHRP URL
Prerequisites
Before you begin, ensure you have the following:
- Node.js and npm – Installed on your system (Node v14+ recommended).
- BSV Wallet – A working Babbage/BSV wallet setup.
- @bsv/sdk – The BSV TypeScript SDK, installed via npm:
npm install @bsv/sdk. - UHRP URL of the file – The content identifier (hash URL) for the file you want to download. You might have obtained this from a previous upload (using StorageUploader) or another source. For example, we'll use a sample UHRP URL in this guide.
Step 1: Instantiate the StorageDownloader
First, import and create an instance of the StorageDownloader. This object will handle contacting the storage overlay network to find and fetch your file. By default, it will use the mainnet (the live BSV network) configuration, but you can specify a network preset if needed.
For example, if you want to use the test network or a local development network, pass a config with the networkPreset option ("mainnet" | "testnet" | "local"). If no config is given, it defaults to mainnet.
1import { StorageDownloader } from '@bsv/sdk';
2
3// Initialize the StorageDownloader (default is mainnet settings)
4const downloader = new StorageDownloader();
5
6// (Optional) If you want to connect to testnet or a local overlay network, use networkPreset:
7// const downloader = new StorageDownloader({ networkPreset: 'testnet' });Step 2: Resolve the UHRP URL to Find Hosts
Once you have a StorageDownloader instance, the next step is to resolve the UHRP URL. Resolving means querying the Babbage storage overlay network to discover which storage servers are holding the file identified by your UHRP hash. This step returns one or more HTTP URLs where the content can be downloaded.
This step is optional but recommended – it lets you see the available host URLs and ensures the file is found before attempting to download. If you skip this, the download method (next step) will internally do the resolution anyway.
1// The UHRP URL of the file to download (example from a test upload)
2const uhrpUrl = 'XUTTCy7KcAn1MdU8SksihCqTnzXc76gbWNXqVMJ5rN1swFTbqbbV';
3
4// Ask the overlay network for hosts that have this content
5const hostUrls = await downloader.resolve(uhrpUrl);
6
7console.log('Hosts advertising the file:', hostUrls);In this code, we call downloader.resolve(uhrpUrl). Under the hood, the SDK contacts a Confederacy host (a known lookup service in the Babbage network) to find advertisements for our file’s hash. It returns an array of URLs for servers that claim to have the file. Each URL is a direct link to a host that you can try for downloading. If hostUrls is empty, that means no host is currently advertising the file – possibly the file has expired or the UHRP URL is invalid. In that case, you won’t be able to download.
Note: You don’t necessarily need to manually pick a host URL from this list – the StorageDownloader can try them for you. But seeing the list can be useful textfor debugging or logging which servers are involved.
Step 3: Download the File and Verify Integrity
Now for the main event: downloading the file. The download method will retrieve the file’s data from one of the hosts and validate it against the hash to ensure integrity. If one host fails or returns bad data, StorageDownloader will automatically try the next available host, making the process resilient. Upon success, it returns a DownloadResult object containing the file’s data and metadata.
Let's call downloader.download(uhrpUrl) and handle the result:
1try {
2 const result = await downloader.download(uhrpUrl);
3 console.log('Download successful!');
4 console.log('MIME type:', result.mimeType);
5 console.log('Data length (bytes):', result.data.length);
6
7 // Example: If running in Node.js, you could save the file to disk:
8 const fs = require('fs');
9 fs.writeFileSync('downloaded_file.bin', Buffer.from(result.data));
10 console.log('File saved as downloaded_file.bin');
11} catch (error) {
12 console.error('Download failed:', error);
13}What’s happening here? We use await downloader.download(uhrpUrl) to fetch the file. Internally, this will:
- Contact the overlay network (if not already resolved) to get host URLs for the content.
- Attempt to download the file from one of the hosts via HTTP.
- Verify that the downloaded data’s hash matches the UHRP URL’s hash (ensuring the content is authentic and uncorrupted).
- Return the file data if everything checks out.
The result we get has two main properties:
result.data– An array of bytes representing the file content. This can be converted to a Buffer (in Node.js) or used as binary data in the browser.result.mimeType– A string indicating the file’s MIME type (content type), as reported by the storage server. For example,"image/png"for a PNG image or"text/plain"for a text file. If the server didn’t provide a type, this could benull, but typically it’s set to the original file’s type.
In the code above, we log the MIME type and data length to confirm we got the file. We also show an example of saving the data to a file in a Node environment by constructing a Buffer from the byte array. In a browser context, you might instead create a Blob and use URL.createObjectURL to trigger a download or display the file (e.g., show an image or play a video). The key point is that at this stage you have the file’s bytes and can handle them as needed.
If the download fails (for instance, if no host had the file or network issues occur), the code will throw an error. We wrap the call in a try/catch to handle any such errors gracefully. On failure, you might check that the UHRP URL is correct, the file is still hosted (within retention period), or try again later.
What’s Next?
Congratulations on downloading a file using StorageDownloader! At this point, you’ve retrieved the content and ensured it’s intact. Here are a few suggestions on what you might explore next:
-
File Integrity Validation: The SDK already verified the file’s hash behind the scenes. For extra assurance or learning purposes, you could manually compute the file’s SHA-256 hash and compare it to the hash encoded in the UHRP URL (The SDK provides utilities like
getHashFromURLto extract the hash bytes from a UHRP URL). This can help you understand how content-addressing works and double-check integrity in custom workflows. -
File Previews and Usage: Now that you have the file data and MIME type, consider how to use it in your application. For example, if it’s an image or video, you can display it directly in a web app by creating a Blob URL or using the data in an
<img>tag. If it’s a document or other data, you could save it to disk (as shown above) or feed it into another part of your program. Learning how to convert the byte array into usable formats (Blob, Buffer, base64, etc.) will be helpful for building user-facing features. -
Retry Mechanisms and Resilience: The
StorageDownloaderis designed to be resilient – it will try multiple hosts if available, ensuring the file can be retrieved from any of them. However, you might still want to implement additional retry logic or user notifications in your app. For instance, if a download fails, you could retry after a short delay, or switch to a different confederacy host (in case the default lookup service is down). You can also log thehostUrls(from the resolve step) and track which host ultimately served the file, building metrics on performance or reliability. Understanding how the overlay network advertises content can inspire strategies for optimizing content delivery in your application.
By following this guide, you’ve mastered the basics of retrieving on-chain stored files using the BSV TypeScript SDK. From here, you can dive deeper into the Babbage ecosystem – for example, try out the StorageUploader to publish your own files, or explore Project Babbage’s documentation for more advanced features like identity management and payment integration. Happy building!
