@ftheirs/msp-client
v3.0.0
Published
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.
Readme
@storagehub-sdk/msp-client
High-level client for interacting with StorageHub MSP (Main Storage Provider) services.
What is this?
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.
Prerequisites
⚠️ Important: This client connects to a StorageHub MSP backend service. You need:
A running MSP backend - Either:
- A production MSP service endpoint, or
- A local MSP backend for development/testing
StorageHub node - The MSP backend requires connection to a StorageHub blockchain node
Quick Backend Setup for Development
To run a local MSP backend with mocks for testing:
# From the StorageHub repository root
RUST_LOG=info cargo run --bin sh-msp-backend --features mocks -- --host 127.0.0.1 --port 8080This starts a mock MSP backend on http://127.0.0.1:8080 that you can use for development.
Install
# pnpm (recommended)
pnpm add @storagehub-sdk/msp-client
# npm
npm i @storagehub-sdk/msp-client
# yarn
yarn add @storagehub-sdk/msp-clientQuick Start
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
Static Methods
MspClient.connect(config)- Create and connect to MSP serviceconfig.baseUrl: string- MSP backend URL (e.g.,http://127.0.0.1:8080)config.timeoutMs?: number- Request timeout in millisecondsconfig.defaultHeaders?: Record<string, string>- Default HTTP headersconfig.fetchImpl?: typeof fetch- Custom fetch implementation
Instance Methods
getHealth()- Check MSP service health and statusgetNonce(address, chainId)- Get authentication message for wallet signingaddress: string- Wallet address (0x...)chainId: number- Blockchain chain ID (1 for Ethereum mainnet)
verify(message, signature)- Verify wallet signature and get auth tokenmessage: string- The message that was signedsignature: string- Wallet signature (0x...)
setToken(token)- Set authentication token for subsequent requestsuploadFile(bucketId, fileKey, file, owner, location)- Upload file to storagebucketId: string- Storage bucket identifierfileKey: string- Unique file key/identifierfile: ReadStream | Blob | File | Uint8Array | ArrayBuffer- File data to uploadowner: string- File ownerlocation: string- File location/path within the bucket
hexToBytes(hex)- Convert hex string to Uint8Array (handles 0x prefix) (TODO: Move tocorepackage)formFileMetadata(owner, bucketId, location, fingerprint, size)- Create FileMetadata instance (TODO: Move tocorepackage underFileMetadata)computeFileKey(metadata)- Compute file key from FileMetadata (TODO: This already exists incorepackage underFileManager, 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 }
- Returns:
listBuckets()- List all buckets of the currently authenticated usergetBucket(bucketId)- Get the metadata of a specific bucketgetFiles(bucketId, options?)- Get the files of a specific bucketbucketId: string- Storage bucket identifieroptions?: { path?: string, signal?: AbortSignal }- Optional parameterspath?: string- Path to the folder to get the files fromsignal?: AbortSignal- Abort signal to cancel the request
