Skip to content
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
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ This Turborepo includes the following example applications:
| Name | Description | Path & Links |
| --- | --- | --- |
| `@shelby-protocol/cross-chain-accounts` | Shelby cross chain accounts example | [`apps/cross-chain-accounts`](./apps/cross-chain-accounts) |
| `shelby-download-example` | An example app to demonstrate downloading blobs using the Shelby SDK | [`apps/download-blob`](./apps/download-blob) |

<!-- APPS_TABLE_END -->

Expand Down
2 changes: 2 additions & 0 deletions apps/download-blob/.env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
SHELBY_ACCOUNT_ADDRESS=0xYourAccountAddressHere
SHELBY_API_KEY=AG-YourApiKeyHere
122 changes: 122 additions & 0 deletions apps/download-blob/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
# Shelby Download Blob Example

An example application demonstrating how to download blobs from the Shelby protocol using the Shelby SDK. This app downloads the specified blob from a Shelby account and saves it to the local filesystem.

## Prerequisites

- Node.js >= 22
- npm, yarn, or pnpm package manager
- A Shelby account with uploaded blobs
- Shelby API key

## Installation

1. Clone the repository and navigate to the download-blob directory:
```bash
cd apps/download-blob
```

2. Install dependencies:
```bash
npm install
# or
yarn install
# or
pnpm install
```

## Environment Variables

Create a `.env` file in the root of this project directory with the following required environment variables. You can copy the `.env.example` file as a starting point:

```bash
cp .env.example .env
```

Then update the values in your `.env` file:

```env
SHELBY_ACCOUNT_ADDRESS=your_account_address_here
SHELBY_API_KEY=your_api_key_here
```

More information on obtaining an API key on the [Shelby docs site](https://docs.shelby.xyz/sdks/typescript/acquire-api-keys).

## Configuration

The example is currently configured to download a blob named `whitepaper.pdf`. You can modify this by changing the `BLOB_NAME` constant in `src/index.ts`:

```typescript
const BLOB_NAME = "your-blob-name.ext" // Change this to your desired blob name
```

## Usage

### Development Mode

Run the example in development mode with automatic rebuilding:

```bash
npm run dev
```

### Production Mode

1. Build the app:
```bash
npm run build
```

2. Run the built app:
```bash
npm start
```

### Direct Execution

You can also run the TypeScript file directly using tsx:

```bash
npx tsx src/index.ts
```

## How It Works

1. **Environment Validation**: The app first validates that all required environment variables are set
2. **Client Initialization**: Creates a Shelby client instance connected to the Shelbynet network
3. **Account Setup**: Uses the account address from the environment variable
4. **Blob Download**: Downloads the specified blob from the Shelby account
5. **File Saving**: Saves the downloaded blob to the `downloads/` directory in the current working directory

## Output

When successful, this example will:
- Create a `downloads/` directory if it doesn't exist
- Download the blob from Shelby
- Save the file as `downloads/whitepaper.pdf` (or whatever `BLOB_NAME` you specified)
- Print progress messages to the console

## Troubleshooting

### Common Issues

1. **SHELBY_ACCOUNT_ADDRESS is not set in .env**
- Ensure you have created a `.env` file with the required variables
- Check that the variable name is spelled correctly

2. **SHELBY_API_KEY is not set in .env**
- Verify your API key is correctly set in the `.env` file
- Ensure there are no extra spaces or quotes around the API key

3. **Blob not found (404)**
- Verify that the blob name specified in `BLOB_NAME` exists in your Shelby account
- Check that the blob name matches exactly
- Ensure you're using the correct account address that contains the blob

4. **Rate limit exceeded (429)**
- Wait a moment before retrying
- Consider implementing exponential backoff for production use

5. **Server errors (500)**
- This indicates an issue with the Shelby service
- Contact Shelby support if this occurs repeatedly
32 changes: 32 additions & 0 deletions apps/download-blob/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
{
"name": "shelby-download-example",
"version": "1.0.0",
"description": "An example app to demonstrate downloading blobs using the Shelby SDK",
"type": "module",
"scripts": {
"start": "tsx --env-file=.env src/index.ts",
"lint": "biome check .",
"fmt": "biome check . --write"
},
"keywords": [
"shelby",
"sdk",
"blob",
"storage"
],
"author": "Akasha <akasha@shelby.xyz>",
"license": "MIT",
"dependencies": {
"@aptos-labs/ts-sdk": "^5.1.1",
"@shelby-protocol/sdk": "^0.0.4"
},
"devDependencies": {
"@biomejs/biome": "2.2.4",
"tsx": "^4.20.5",
"typescript": "^5.9.2",
"vitest": "^3.2.4"
},
"engines": {
"node": ">=22"
}
}
46 changes: 46 additions & 0 deletions apps/download-blob/src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
// download.ts — run with: npx tsx download.ts

import { createWriteStream, mkdirSync } from "node:fs";
import { dirname, join } from "node:path";
import { Readable } from "node:stream";
import { pipeline } from "node:stream/promises";
import type { ReadableStream } from "node:stream/web";
import { AccountAddress, Network } from "@aptos-labs/ts-sdk";
import { ShelbyNodeClient } from "@shelby-protocol/sdk/node";

if (!process.env.SHELBY_API_KEY) {
throw new Error("Missing SHELBY_API_KEY");
}
if (!process.env.SHELBY_ACCOUNT_ADDRESS) {
throw new Error("Missing SHELBY_ACCOUNT_ADDRESS");
}

// The blob name as stored in Shelby (must match what you uploaded or already have).
const BLOB_NAME = "whitepaper.pdf";

// Where to save the downloaded file locally.
const OUT_PATH = join(process.cwd(), "downloads", BLOB_NAME);

// 1) Initialize a Shelby client (auth via API key; target shelbynet).
const client = new ShelbyNodeClient({
network: Network.SHELBYNET,
apiKey: process.env.SHELBY_API_KEY, // ensure .env is loaded
});

// 2) Parse the account address you'll download from.
// ⚠️ This should be the *same account* that previously uploaded the blob.
const account = AccountAddress.fromString(process.env.SHELBY_ACCOUNT_ADDRESS);

// 3) Ask Shelby for a readable Web stream of the blob bytes.
const { readable } = await client.download({ account, blobName: BLOB_NAME });

// 4) Make sure the output directory exists.
mkdirSync(dirname(OUT_PATH), { recursive: true });

// 5) Pipe the Web stream directly to a Node write stream (no buffering).
await pipeline(
Readable.fromWeb(readable as ReadableStream<Uint8Array>),
createWriteStream(OUT_PATH),
);

console.log("✓ Saved to", OUT_PATH);
25 changes: 25 additions & 0 deletions apps/download-blob/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
{
"compilerOptions": {
"target": "ES2022",
"module": "ESNext",
"moduleResolution": "bundler",
"allowSyntheticDefaultImports": true,
"esModuleInterop": true,
"allowJs": true,
"strict": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true,
"declaration": true,
"declarationMap": true,
"sourceMap": true,
"outDir": "./dist",
"rootDir": "./src",
"resolveJsonModule": true,
"isolatedModules": true,
"noEmit": false,
"lib": ["ES2022", "DOM"],
"types": ["node", "vitest/globals"]
},
"include": ["src/**/*"],
"exclude": ["node_modules", "dist", "**/*.test.ts"]
}
Loading