// Use when integrating Shelby Protocol TypeScript SDK for Node.js or browser applications. Helps with setup, blob uploads, authentication with Aptos accounts, network configuration, and SDK implementation patterns. Invoke for programmatic Shelby storage integration, decentralized blob APIs, or building apps with Shelby.
| name | shelby-sdk-integration |
| description | Use when integrating Shelby Protocol TypeScript SDK for Node.js or browser applications. Helps with setup, blob uploads, authentication with Aptos accounts, network configuration, and SDK implementation patterns. Invoke for programmatic Shelby storage integration, decentralized blob APIs, or building apps with Shelby. |
| allowed-tools | Read, Write, Edit, Grep, Glob |
| model | sonnet |
This skill assists developers integrating the Shelby Protocol TypeScript SDK into Node.js or browser applications. It provides guidance on installation, authentication, blob upload/download operations, and best practices for working with Shelby's decentralized storage network.
This skill should be invoked when:
Install required packages:
For Node.js and browser projects:
npm install @shelby-protocol/sdk @aptos-labs/ts-sdk
# or
pnpm add @shelby-protocol/sdk @aptos-labs/ts-sdk
# or
yarn add @shelby-protocol/sdk @aptos-labs/ts-sdk
# or
bun add @shelby-protocol/sdk @aptos-labs/ts-sdk
Node.js Setup:
import { Network } from '@aptos-labs/ts-sdk';
import { ShelbyNodeClient } from "@shelby-protocol/sdk/node";
// Configure Shelby client with network settings
const client = new ShelbyNodeClient({
network: Network.SHELBYNET
});
Browser Setup:
import { Network } from '@aptos-labs/ts-sdk';
import { ShelbyClient } from "@shelby-protocol/sdk/browser";
const config = {
network: Network.SHELBYNET,
apiKey: process.env.SHELBY_API_KEY, // Optional
};
const shelbyClient = new ShelbyClient(config);
Create account signer using Ed25519 private keys:
import { Ed25519PrivateKey, Account } from '@aptos-labs/ts-sdk';
// IMPORTANT: Store private keys securely, never commit to version control
const privateKey = new Ed25519PrivateKey(process.env.SHELBY_PRIVATE_KEY);
const account = Account.fromPrivateKey({ privateKey });
Best practices for key management:
Basic upload implementation:
// Prepare blob data
const blobData = Buffer.from('Hello, Shelby!');
const blobName = 'example/hello.txt';
// Calculate expiration in microseconds (30 days from now)
const expirationMicros = (1000 * 60 * 60 * 24 * 30 + Date.now()) * 1000;
// Upload to Shelby network
await client.upload({
signer: account,
blobData: blobData,
blobName: blobName,
expirationMicros: expirationMicros
});
Upload parameters explained:
Upload file from filesystem (Node.js):
import fs from 'fs';
import path from 'path';
async function uploadFile(filePath: string, blobName: string, expirationDays: number) {
// Read file as Buffer
const blobData = fs.readFileSync(filePath);
// Calculate expiration
const expirationMicros = (1000 * 60 * 60 * 24 * expirationDays + Date.now()) * 1000;
// Upload
await client.upload({
signer: account,
blobData,
blobName,
expirationMicros
});
console.log(`Uploaded ${path.basename(filePath)} as ${blobName}`);
}
// Usage
await uploadFile('./video.mp4', 'videos/intro.mp4', 30);
Upload from user input (Browser):
async function uploadFromFileInput(file: File, expirationDays: number) {
// Convert File to ArrayBuffer then Uint8Array
const arrayBuffer = await file.arrayBuffer();
const blobData = new Uint8Array(arrayBuffer);
const blobName = `uploads/${Date.now()}_${file.name}`;
const expirationMicros = (1000 * 60 * 60 * 24 * expirationDays + Date.now()) * 1000;
await shelbyClient.upload({
signer: account,
blobData,
blobName,
expirationMicros
});
return blobName;
}
// Usage with input element
const fileInput = document.querySelector<HTMLInputElement>('#fileInput');
fileInput?.addEventListener('change', async (e) => {
const file = (e.target as HTMLInputElement).files?.[0];
if (file) {
const blobName = await uploadFromFileInput(file, 30);
console.log('Uploaded as:', blobName);
}
});
Robust error handling pattern:
async function safeUpload(blobData: Buffer, blobName: string, expirationMicros: number) {
try {
await client.upload({
signer: account,
blobData,
blobName,
expirationMicros
});
return { success: true, blobName };
} catch (error) {
// Handle common errors
if (error.message.includes('insufficient ShelbyUSD')) {
console.error('Insufficient ShelbyUSD tokens. Fund account at faucet.');
return { success: false, error: 'INSUFFICIENT_SHELBYUSD' };
}
if (error.message.includes('insufficient gas')) {
console.error('Insufficient Aptos tokens for gas fees.');
return { success: false, error: 'INSUFFICIENT_GAS' };
}
if (error.message.includes('network')) {
console.error('Network error. Check connectivity.');
return { success: false, error: 'NETWORK_ERROR' };
}
console.error('Upload failed:', error);
return { success: false, error: 'UNKNOWN', details: error };
}
}
Available networks:
import { Network } from '@aptos-labs/ts-sdk';
// Production Shelbynet
const prodClient = new ShelbyNodeClient({
network: Network.SHELBYNET
});
// Local development network
const devClient = new ShelbyNodeClient({
network: Network.LOCAL
});
Configure with API key (optional but recommended):
const client = new ShelbyClient({
network: Network.SHELBYNET,
apiKey: process.env.SHELBY_API_KEY // Avoids rate limiting
});
When helping users integrate Shelby SDK:
videos/2024/intro.mp4user123/uploads/2024-01-15_document.pdf${Date.now()}_${originalName}const EXPIRATION = {
DAY: 1000 * 60 * 60 * 24,
WEEK: 1000 * 60 * 60 * 24 * 7,
MONTH: 1000 * 60 * 60 * 24 * 30,
};
(milliseconds + Date.now()) * 1000User Request: "Set up Shelby SDK in my Node.js application to upload files"
Implementation:
// src/shelby-client.ts
import { Network, Ed25519PrivateKey, Account } from '@aptos-labs/ts-sdk';
import { ShelbyNodeClient } from "@shelby-protocol/sdk/node";
import fs from 'fs';
export class ShelbyService {
private client: ShelbyNodeClient;
private account: Account;
constructor() {
// Initialize client
this.client = new ShelbyNodeClient({
network: Network.SHELBYNET
});
// Setup authentication
const privateKey = new Ed25519PrivateKey(process.env.SHELBY_PRIVATE_KEY!);
this.account = Account.fromPrivateKey({ privateKey });
}
async uploadFile(filePath: string, blobName: string, expirationDays: number = 30) {
const blobData = fs.readFileSync(filePath);
const expirationMicros = (1000 * 60 * 60 * 24 * expirationDays + Date.now()) * 1000;
await this.client.upload({
signer: this.account,
blobData,
blobName,
expirationMicros
});
return blobName;
}
}
// Usage
const shelby = new ShelbyService();
await shelby.uploadFile('./video.mp4', 'videos/demo.mp4', 30);
User Request: "Create a React component to upload files to Shelby"
Implementation:
// components/ShelbyUploader.tsx
import React, { useState } from 'react';
import { Network, Ed25519PrivateKey, Account } from '@aptos-labs/ts-sdk';
import { ShelbyClient } from "@shelby-protocol/sdk/browser";
const shelbyClient = new ShelbyClient({
network: Network.SHELBYNET,
apiKey: process.env.REACT_APP_SHELBY_API_KEY
});
const privateKey = new Ed25519PrivateKey(process.env.REACT_APP_SHELBY_PRIVATE_KEY!);
const account = Account.fromPrivateKey({ privateKey });
export function ShelbyUploader() {
const [uploading, setUploading] = useState(false);
const [uploadedUrl, setUploadedUrl] = useState<string | null>(null);
const handleUpload = async (e: React.ChangeEvent<HTMLInputElement>) => {
const file = e.target.files?.[0];
if (!file) return;
setUploading(true);
try {
// Convert file to Uint8Array
const arrayBuffer = await file.arrayBuffer();
const blobData = new Uint8Array(arrayBuffer);
// Generate blob name
const blobName = `uploads/${Date.now()}_${file.name}`;
// Upload with 30 day expiration
const expirationMicros = (1000 * 60 * 60 * 24 * 30 + Date.now()) * 1000;
await shelbyClient.upload({
signer: account,
blobData,
blobName,
expirationMicros
});
// Construct URL for accessing uploaded blob
const url = `https://api.shelbynet.shelby.xyz/shelby/blobs/${blobName}`;
setUploadedUrl(url);
alert('Upload successful!');
} catch (error) {
console.error('Upload failed:', error);
alert('Upload failed. Check console for details.');
} finally {
setUploading(false);
}
};
return (
<div>
<input
type="file"
onChange={handleUpload}
disabled={uploading}
/>
{uploading && <p>Uploading...</p>}
{uploadedUrl && <p>URL: {uploadedUrl}</p>}
</div>
);
}
User Request: "Build a service to upload videos to Shelby with progress tracking"
Implementation:
// services/video-upload.ts
import { Network, Ed25519PrivateKey, Account } from '@aptos-labs/ts-sdk';
import { ShelbyNodeClient } from "@shelby-protocol/sdk/node";
import fs from 'fs';
import path from 'path';
interface UploadProgress {
filename: string;
status: 'pending' | 'uploading' | 'completed' | 'failed';
blobName?: string;
error?: string;
}
export class VideoUploadService {
private client: ShelbyNodeClient;
private account: Account;
constructor() {
this.client = new ShelbyNodeClient({ network: Network.SHELBYNET });
const privateKey = new Ed25519PrivateKey(process.env.SHELBY_PRIVATE_KEY!);
this.account = Account.fromPrivateKey({ privateKey });
}
async uploadVideo(
videoPath: string,
category: string = 'videos',
expirationDays: number = 90
): Promise<UploadProgress> {
const filename = path.basename(videoPath);
const blobName = `${category}/${Date.now()}_${filename}`;
const progress: UploadProgress = {
filename,
status: 'pending'
};
try {
progress.status = 'uploading';
const blobData = fs.readFileSync(videoPath);
const expirationMicros = (1000 * 60 * 60 * 24 * expirationDays + Date.now()) * 1000;
await this.client.upload({
signer: this.account,
blobData,
blobName,
expirationMicros
});
progress.status = 'completed';
progress.blobName = blobName;
console.log(`✅ Uploaded: ${filename} -> ${blobName}`);
} catch (error) {
progress.status = 'failed';
progress.error = error instanceof Error ? error.message : 'Unknown error';
console.error(`❌ Failed: ${filename}`, error);
}
return progress;
}
async uploadMultipleVideos(videoPaths: string[]): Promise<UploadProgress[]> {
const results: UploadProgress[] = [];
for (const videoPath of videoPaths) {
const result = await this.uploadVideo(videoPath);
results.push(result);
}
return results;
}
getBlobUrl(blobName: string): string {
return `https://api.shelbynet.shelby.xyz/shelby/blobs/${blobName}`;
}
}
// Usage
const uploader = new VideoUploadService();
const result = await uploader.uploadVideo('./intro.mp4', 'tutorials', 90);
const url = uploader.getBlobUrl(result.blobName!);
console.log('Access video at:', url);
Common errors and solutions:
Cannot find module '@shelby-protocol/sdk': Package not installed → Run npm/pnpm/yarn/bun installInsufficient ShelbyUSD tokens: Fund account via faucet or CLIInsufficient gas: Fund with Aptos tokensInvalid private key format: Ensure key is valid Ed25519 private keyNetwork error: Check internet connectivity and API endpointInvalid blob data: Ensure data is Buffer (Node.js) or Uint8Array (browser)Expiration validation error: Ensure expiration is in microseconds and in future@shelby-protocol/sdk/node) and Browser (@shelby-protocol/sdk/browser)https://api.shelbynet.shelby.xyz/shelbyhttps://api.shelbynet.shelby.xyz/shelby/blobs/{blobName}@shelby-protocol/player)