High-level TypeScript client for StorageHub MSP: simple file upload/download, SIWE-style auth, health checks, and bucket browsing built on top of @storagehub-sdk/core.
npm install @ftheirs/msp-clientHigh-level client for interacting with StorageHub MSP (Main Storage Provider) services.
The @storagehub-sdk/msp-client is a TypeScript client library that provides a simple, high-level interface for:
- File Storage & Retrieval: Upload and download files to/from StorageHub MSP services
- Authentication: SIWE-style (Sign-In With Ethereum) authentication with MSP providers
- Health Monitoring: Check MSP service availability and status
- Bucket Management: Interact with storage buckets, listing the existent ones, getting their metadata and the files they contain
This package is built on top of @storagehub-sdk/core and provides a more convenient API for common MSP operations, abstracting away the lower-level details.
⚠️ Important: This client connects to a StorageHub MSP backend service. You need:
1. A running MSP backend - Either:
- A production MSP service endpoint, or
- A local MSP backend for development/testing
2. StorageHub node - The MSP backend requires connection to a StorageHub blockchain node
To run a local MSP backend with mocks for testing:
``bash`From the StorageHub repository root
RUST_LOG=info cargo run --bin sh-msp-backend --features mocks -- --host 127.0.0.1 --port 8080
This starts a mock MSP backend on http://127.0.0.1:8080 that you can use for development.
`bashpnpm (recommended)
pnpm add @storagehub-sdk/msp-client
Quick Start
`ts
import { MspClient } from '@storagehub-sdk/msp-client';
import { createReadStream, createWriteStream } from 'node:fs';
import { Readable } from 'node:stream';// 1. Connect to MSP service
const client = await MspClient.connect({
baseUrl: 'http://127.0.0.1:8080' // Your MSP backend URL
});
// 2. Check service health
const health = await client.getHealth();
console.log('MSP service health:', health);
// 3. Authenticate with wallet (SIWE-style)
const walletAddress = '0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266';
const chainId = 1; // Ethereum mainnet
// Get authentication message to sign
const { message } = await client.getNonce(walletAddress, chainId);
console.log('Sign this message with your wallet:', message);
// After signing with your wallet (e.g., MetaMask, WalletConnect, etc.)
const signature = '0xYourWalletSignature...'; // Replace with actual signature
const verified = await client.verify(message, signature);
client.setToken(verified.token); // Set auth token for subsequent requests
// 4. Upload a file
const bucketId = '0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef'; // StorageHub bucket identifier
const fileKey = '0xabcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890'; // Unique file identifier
const filePath = './myfile.txt';
const owner = walletAddress; // File owner
const location = 'myfile.txt'; // File location/path within the bucket
const receipt = await client.uploadFile(bucketId, fileKey, createReadStream(filePath), owner, location);
console.log('File uploaded successfully:', receipt);
// 5. Download the file
const download = await client.downloadByKey(fileKey);
const outputPath = './downloaded-file.txt';
// Stream the download to a file
const writeStream = createWriteStream(outputPath);
Readable.fromWeb(download.stream).pipe(writeStream);
await new Promise((resolve, reject) => {
writeStream.on('finish', resolve);
writeStream.on('error', reject);
});
console.log('File downloaded successfully to:', outputPath);
console.log('Download status:', download.status);
// 6. List the buckets of the currently authenticated user
const buckets = await client.listBuckets();
console.log('Buckets:', buckets);
// 7. Get the metadata of a specific bucket
const bucket = await client.getBucket(bucketId);
console.log('Bucket:', bucket);
// 8. Get the files of the root folder of a specific bucket
const files = await client.getFiles(bucketId);
console.log('Root files:', files);
// 9. Get the files of a specific folder of a specific bucket
const files = await client.getFiles(bucketId, { path: '/path/to/folder' });
console.log('Folder files:', files);
`API Reference
$3
- MspClient.connect(config) - Create and connect to MSP service
- config.baseUrl: string - MSP backend URL (e.g., http://127.0.0.1:8080)
- config.timeoutMs?: number - Request timeout in milliseconds
- config.defaultHeaders?: Record - Default HTTP headers
- config.fetchImpl?: typeof fetch - Custom fetch implementation$3
- getHealth() - Check MSP service health and status
- getNonce(address, chainId) - Get authentication message for wallet signing
- address: string - Wallet address (0x...)
- chainId: number - Blockchain chain ID (1 for Ethereum mainnet)
- verify(message, signature) - Verify wallet signature and get auth token
- message: string - The message that was signed
- signature: string - Wallet signature (0x...)
- setToken(token) - Set authentication token for subsequent requests
- uploadFile(bucketId, fileKey, file, owner, location) - Upload file to storage
- bucketId: string - Storage bucket identifier
- fileKey: string - Unique file key/identifier
- file: ReadStream | Blob | File | Uint8Array | ArrayBuffer - File data to upload
- owner: string - File owner
- location: string - File location/path within the bucket
- hexToBytes(hex) - Convert hex string to Uint8Array (handles 0x prefix) (TODO: Move to core package)
- formFileMetadata(owner, bucketId, location, fingerprint, size) - Create FileMetadata instance (TODO: Move to core package under FileMetadata)
- computeFileKey(metadata) - Compute file key from FileMetadata (TODO: This already exists in core package under FileManager, but requires a file stream to be provided, make it more flexible there and remove it here)
- downloadByKey(fileKey) - Download file by key
- Returns: { stream: ReadableStream, status: string }
- listBuckets() - List all buckets of the currently authenticated user
- getBucket(bucketId) - Get the metadata of a specific bucket
- getFiles(bucketId, options?) - Get the files of a specific bucket
- bucketId: string - Storage bucket identifier
- options?: { path?: string, signal?: AbortSignal } - Optional parameters
- path?: string - Path to the folder to get the files from
- signal?: AbortSignal` - Abort signal to cancel the request