UNPKG

@stoar/cli

Version:

CLI tool for STOAR - decentralized file storage on Arweave

131 lines 5.03 kB
import { Command } from 'commander'; import { getWalletConfig, formatArweaveAmount } from '../utils/wallet.js'; import { output, success, createSpinner, formatBytes } from '../utils/output.js'; import { wrapCommand } from '../utils/error.js'; import { readFileSync, statSync } from 'node:fs'; import { basename } from 'node:path'; import { glob } from 'glob'; import { getMimeType } from '@stoar/sdk'; export const uploadCommand = new Command('upload') .description('Upload files to Arweave') .argument('<files...>', 'Files to upload (supports glob patterns)') .option('-n, --name <name>', 'File name override') .option('-t, --tags <tags>', 'Tags in key=value,key2=value2 format') .option('-b, --batch', 'Upload multiple files as a batch') .action(wrapCommand(async (files, options, command) => { const globalOptions = command.parent?.opts() || {}; // Expand glob patterns const expandedFiles = []; for (const pattern of files) { const matches = await glob(pattern); if (matches.length === 0) { throw new Error(`No files found matching pattern: ${pattern}`); } expandedFiles.push(...matches); } // Parse tags const tags = {}; if (options.tags) { const tagPairs = options.tags.split(','); for (const pair of tagPairs) { const [key, value] = pair.split('='); if (key && value) { tags[key] = value; } } } const { client } = await getWalletConfig(globalOptions); // Check if we should use batch mode const shouldBatch = options.batch || expandedFiles.length > 1; if (shouldBatch) { await uploadBatch(expandedFiles, client, tags, globalOptions); } else { await uploadSingle(expandedFiles[0], client, tags, options.name, globalOptions); } })); async function uploadSingle(filePath, client, tags, nameOverride, globalOptions) { const spinner = createSpinner(`Uploading ${basename(filePath)}...`); spinner.start(); try { const fileData = readFileSync(filePath); const stats = statSync(filePath); const fileName = nameOverride || basename(filePath); const result = await client.uploadFile(fileData, { name: fileName, size: stats.size, contentType: getMimeType(filePath) }, { tags, progress: (percentage) => { spinner.text = `Uploading ${fileName}... ${Math.round(percentage)}%`; } }); spinner.stop(); const uploadData = { transactionId: result.id, url: `https://arweave.net/${result.id}`, fileName, size: formatBytes(stats.size), cost: result.reward ? formatArweaveAmount(result.reward) : 'Pending confirmation' }; output(uploadData, globalOptions); if (!globalOptions?.json && !globalOptions?.quiet) { success(`Uploaded: ${uploadData.url}`); console.log(` Cost: ${uploadData.cost}`); } } catch (err) { spinner.stop(); throw err; } } async function uploadBatch(filePaths, client, tags, globalOptions) { const spinner = createSpinner(`Preparing batch upload of ${filePaths.length} files...`); spinner.start(); try { // Create batch const batchId = client.createBatch(); let totalSize = 0; const uploadResults = []; // Add files to batch for (const filePath of filePaths) { const fileData = readFileSync(filePath); const stats = statSync(filePath); totalSize += stats.size; const result = await client.uploadFile(fileData, { name: basename(filePath), size: stats.size, contentType: getMimeType(filePath) }, { tags, batch: batchId }); uploadResults.push(result); spinner.text = `Added ${basename(filePath)} to batch...`; } spinner.text = 'Committing batch...'; const batchStatus = await client.commitBatch(batchId); spinner.stop(); const batchData = { bundleId: batchStatus.bundleId, url: `https://arweave.net/${batchStatus.bundleId}`, fileCount: filePaths.length, totalSize: formatBytes(totalSize), cost: batchStatus.totalCost ? `${batchStatus.totalCost} AR` : 'N/A', items: uploadResults }; output(batchData, globalOptions); if (!globalOptions?.json && !globalOptions?.quiet) { success(`Batch uploaded: ${batchData.url}`); console.log(` Files: ${batchData.fileCount}`); console.log(` Total size: ${batchData.totalSize}`); console.log(` Total cost: ${batchData.cost}`); } } catch (err) { spinner.stop(); throw err; } } //# sourceMappingURL=upload.js.map