UNPKG

@stoar/sdk

Version:

JavaScript/TypeScript SDK for STOAR - Decentralized file storage on Arweave

511 lines (390 loc) โ€ข 12.3 kB
# STOAR SDK [![npm version](https://badge.fury.io/js/%40stoar%2Fsdk.svg)](https://www.npmjs.com/package/@stoar/sdk) [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://opensource.org/licenses/MIT) [![TypeScript](https://img.shields.io/badge/TypeScript-Ready-blue.svg)](https://www.typescriptlang.org/) [![Bundle Size](https://img.shields.io/bundlephobia/minzip/@stoar/sdk)](https://bundlephobia.com/package/@stoar/sdk) A TypeScript/JavaScript SDK for interacting with STOAR - a decentralized file storage system built on Arweave. ## Features - ๐Ÿš€ **Simple API**: Easy-to-use client for file uploads and management - ๐Ÿ” **Wallet Support**: Compatible with ArConnect browser extension and JSON wallet files - ๐Ÿ“ฆ **Batch Uploads**: Efficient batch file uploads using AR bundles - ๐Ÿ”„ **S3 Compatibility**: Familiar S3-like API for easy migration - ๐Ÿ’พ **Permanent Storage**: Leverage Arweave's permanent, decentralized storage - ๐Ÿงช **Well Tested**: Comprehensive unit and integration tests - ๐Ÿ“˜ **TypeScript**: Full TypeScript support with complete type definitions ## Installation ```bash npm install @stoar/sdk # or yarn add @stoar/sdk # or bun add @stoar/sdk ``` ## Quick Start ### Basic File Upload ```typescript import { StoarClient } from '@stoar/sdk'; // Initialize client const client = new StoarClient({ appName: 'My App', appVersion: '1.0.0' }); // Initialize with ArConnect wallet (browser) await client.init(); // Upload a file const file = new Uint8Array([1, 2, 3, 4]); const result = await client.uploadFile(file, { name: 'my-file.bin', size: file.length, contentType: 'application/octet-stream' }); console.log('Uploaded!', result.url); ``` ### Using JSON Wallet ```typescript import { StoarClient } from '@stoar/sdk'; import fs from 'fs'; // Load wallet from file const walletData = fs.readFileSync('path/to/wallet.json', 'utf8'); const client = new StoarClient(); await client.init(walletData); // Upload file const result = await client.uploadFile( Buffer.from('Hello, Arweave!'), { name: 'hello.txt', size: 15, contentType: 'text/plain' } ); ``` ### Batch Upload STOAR SDK now supports advanced batching capabilities that significantly reduce transaction costs: #### Method 1: Auto-batching ```typescript // Enable auto-batching - all subsequent uploads are automatically bundled client.enableBatching({ timeout: 30000, // Auto-commit after 30 seconds maxFiles: 100, // Or when 100 files are added maxBytes: 100 * 1024 * 1024 // Or when 100MB is reached }); // These uploads are automatically batched together await client.uploadFile(data1, metadata1); await client.uploadFile(data2, metadata2); await client.uploadFile(data3, metadata3); // Disable and commit any remaining files await client.disableBatching(); ``` #### Method 2: Manual batch control ```typescript // Create a batch const batchId = client.createBatch({ maxFiles: 50, autoCommit: false // Manual control }); // Add files to the batch await client.uploadFile(data1, metadata1, { batch: batchId }); await client.uploadFile(data2, metadata2, { batch: batchId }); // Check batch status const status = client.getBatchStatus(batchId); console.log(`Files in batch: ${status.fileCount}`); // Commit when ready const result = await client.commitBatch(batchId); console.log(`Bundle created: ${result.bundleId}`); console.log(`Cost savings: ${result.fileCount - 1} transaction fees saved!`); ``` #### Method 3: Direct batch upload ```typescript const files = [ { data: Buffer.from('File 1 content'), metadata: { name: 'file1.txt', size: 14, contentType: 'text/plain' } }, { data: Buffer.from('File 2 content'), metadata: { name: 'file2.txt', size: 14, contentType: 'text/plain' } } ]; const batchResult = await client.uploadBatch(files, { bundleTags: { 'Batch-Name': 'My Batch Upload' }, progress: (status) => { console.log(`Progress: ${status.completed}/${status.total}`); } }); console.log('Batch uploaded!', batchResult.bundleUrl); ``` **Benefits of Batching:** - ๐Ÿ’ฐ **90%+ cost reduction** for multi-file uploads - ๐Ÿš€ **Faster uploads** with single network transaction - โšก **Atomic operations** - all files succeed or fail together - ๐Ÿ“Š **Perfect for NFT collections** and bulk data ## S3 Compatibility Layer For easy migration from S3-based applications: ```typescript import { StoarClient, StoarS3Client } from '@stoar/sdk'; const client = new StoarClient(); await client.init(); const s3 = new StoarS3Client(client, { bucket: 'my-bucket', region: 'us-east-1' }); // Use familiar S3 API await s3.putObject({ Key: 'path/to/file.txt', Body: 'Hello, S3 compatibility!', ContentType: 'text/plain', Metadata: { author: 'John Doe', version: '1.0' } }); // Retrieve object const object = await s3.getObject({ Key: 'path/to/file.txt' }); console.log(new TextDecoder().decode(object.Body)); // List objects const list = await s3.listObjects({ Prefix: 'path/' }); console.log(list.Contents); ``` ## API Reference ### StoarClient #### Constructor ```typescript new StoarClient(config?: StoarConfig) ``` **StoarConfig Options:** - `arweave?: Arweave` - Custom Arweave instance - `gateway?: string` - Arweave gateway URL (default: 'https://arweave.net') - `wallet?: string | ArrayBuffer | object` - Wallet data - `appName?: string` - Application name for tagging - `appVersion?: string` - Application version for tagging #### Methods ##### `init(walletSource?)` Initialize the client with a wallet. ```typescript // Browser wallet (ArConnect) await client.init(); // JSON wallet string await client.init(jsonWalletString); // JWK object await client.init(jwkObject); // ArrayBuffer await client.init(walletArrayBuffer); ``` ##### `uploadFile(data, metadata, options?)` Upload a single file (supports batching). ```typescript await client.uploadFile( data: Buffer | Uint8Array | string, metadata: { name: string; size: number; contentType: string; lastModified?: number; }, options?: { tags?: Record<string, string>; contentType?: string; encrypt?: boolean; progress?: (progress: number) => void; batch?: boolean | string; // Enable batching or specify batch ID } ); ``` ##### `uploadBatch(files, options?)` Upload multiple files as a bundle. ```typescript await client.uploadBatch( files: Array<{ data: Buffer | Uint8Array; metadata: FileMetadata; }>, options?: { tags?: Record<string, string>; bundleTags?: Record<string, string>; progress?: (progress: { completed: number; total: number; current?: string; }) => void; concurrent?: number; } ); ``` ##### `query(options?)` Query transactions using Arweave's GraphQL endpoint. This method has been updated to use GraphQL instead of the deprecated ArQL, providing better performance and more reliable results. ```typescript // Basic query const results = await client.query({ limit: 20, owner: 'wallet-address' }); // Query with tags const taggedResults = await client.query({ tags: { 'App-Name': 'STOAR SDK', 'Content-Type': 'image/png' }, limit: 50 }); // Pagination with cursor const page2 = await client.query({ limit: 20, after: 'cursor-from-previous-query' }); // Filter by block height const recentTxs = await client.query({ minBlock: 1000000, maxBlock: 1100000 }); ``` **Query Options:** - `limit`: Number of results to return (default: 10) - `after`: Cursor for pagination - `tags`: Filter by transaction tags - `owner`: Filter by wallet address - `minBlock`: Minimum block height - `maxBlock`: Maximum block height **Returns:** Array of `QueryResult` objects containing: - `id`: Transaction ID - `owner`: Owner wallet address - `tags`: Transaction tags as key-value pairs - `block`: Block information (height and timestamp) - `fee`: Transaction fee in winston - `quantity`: Transfer amount in winston ##### `getFile(transactionId)` Retrieve file data by transaction ID. ```typescript const data: Uint8Array = await client.getFile('transaction-id'); ``` ##### `getAddress()` Get wallet address. ```typescript const address: string = client.getAddress(); ``` ##### `getBalance()` Get wallet balance in AR. ```typescript const balance: string = await client.getBalance(); ``` ##### `createBatch(options?)` Create a new batch for bundling files. ```typescript const batchId: string = client.createBatch({ maxFiles?: number; // Maximum files in batch maxBytes?: number; // Maximum total size timeout?: number; // Auto-commit timeout in ms autoCommit?: boolean; // Enable auto-commit }); ``` ##### `commitBatch(batchId)` Commit a batch and upload as bundle. ```typescript const result: BatchCommitResult = await client.commitBatch(batchId); // Returns: { batchId, bundleId, bundleUrl, fileCount, totalSize, totalCost, files } ``` ##### `getBatchStatus(batchId)` Get the current status of a batch. ```typescript const status: BatchStatus = client.getBatchStatus(batchId); // Returns: { batchId, fileCount, totalSize, status, createdAt, error? } ``` ##### `enableBatching(options?)` Enable auto-batching for all subsequent uploads. ```typescript client.enableBatching({ timeout?: number; // Auto-commit timeout maxFiles?: number; // Max files before auto-commit maxBytes?: number; // Max size before auto-commit }); ``` ##### `disableBatching()` Disable auto-batching and commit any pending files. ```typescript const result = await client.disableBatching(); // Returns BatchCommitResult if files were pending, void otherwise ``` ### StoarS3Client S3-compatible interface for STOAR. #### Constructor ```typescript new StoarS3Client(stoarClient: StoarClient, config: S3CompatibleConfig) ``` #### Methods - `putObject(params)` - Upload an object - `getObject(params)` - Retrieve an object - `deleteObject(params)` - Delete an object (creates delete marker) - `headObject(params)` - Get object metadata - `listObjects(params)` - List objects in bucket - `copyObject(params)` - Copy an object ## Error Handling The SDK provides specific error types: ```typescript import { StoarError, UploadError, BundleError, WalletError, InsufficientBalanceError } from '@stoar/sdk'; try { await client.uploadFile(data, metadata); } catch (error) { if (error instanceof InsufficientBalanceError) { console.error('Insufficient balance:', error.message); console.error('Required:', error.required, 'AR'); console.error('Available:', error.available, 'AR'); } else if (error instanceof UploadError) { console.error('Upload failed:', error.message); } else if (error instanceof WalletError) { console.error('Wallet error:', error.message); } else if (error instanceof BundleError) { console.error('Bundle error:', error.message); } } ``` ## Environment Configuration You can configure the SDK using environment variables: ```bash # Custom Arweave gateway ARWEAVE_GATEWAY=https://arweave.net # Application info APP_NAME=MyApp APP_VERSION=1.0.0 ``` ## Development ### Building ```bash bun run build ``` ### Testing ```bash # Run tests bun run test # Run tests with UI bun run test:ui # Run tests with coverage bun run test:coverage ``` ### Linting ```bash bun run lint bun run lint:fix ``` ## Examples Check out the `examples/` directory for more usage examples: - [Batch Upload](examples/batch-upload.ts) - Comprehensive batch upload examples - [NFT Batch Explained](examples/nft-batch-explained.ts) - How to upload NFT collections efficiently - [S3 Storage Test](examples/s3-storage-test.ts) - S3 compatibility layer examples - [S3 Upload Test](examples/s3-test-upload.ts) - S3-style uploads - [S3 Query Test](examples/s3-test-query.ts) - Querying with S3 interface ## Contributing 1. Fork the repository 2. Create your feature branch (`git checkout -b feature/amazing-feature`) 3. Commit your changes (`git commit -m 'Add some amazing feature'`) 4. Push to the branch (`git push origin feature/amazing-feature`) 5. Open a Pull Request ## License This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details. ## Support - ๐Ÿ“– [Documentation](https://stoar.io/sdk) - ๐Ÿ› [Report Issues](https://github.com/micovi/stoar/issues)