@stoar/cli
Version:
CLI tool for STOAR - decentralized file storage on Arweave
112 lines • 5.22 kB
JavaScript
import { Command } from 'commander';
import { output, createSpinner, formatBytes, createTable } from '../utils/output.js';
import { wrapCommand } from '../utils/error.js';
import { getArweave } from '../utils/arweave.js';
import { fetchAndParseBundle } from '../utils/bundle.js';
export const infoCommand = new Command('info')
.description('Get information about a file or transaction')
.argument('<txId>', 'Transaction ID to get info for')
.action(wrapCommand(async (txId, options, command) => {
const globalOptions = command.parent?.opts() || {};
const spinner = createSpinner(`Fetching transaction ${txId}...`);
spinner.start();
try {
// Get Arweave instance
const Arweave = await getArweave();
const arweave = Arweave.init({
host: 'arweave.net',
port: 443,
protocol: 'https'
});
// Get transaction
const tx = await arweave.transactions.get(txId);
const status = await arweave.transactions.getStatus(txId);
spinner.stop();
// Extract tags
const tags = {};
tx.get('tags').forEach((tag) => {
const key = tag.get('name', { decode: true, string: true });
const value = tag.get('value', { decode: true, string: true });
tags[key] = value;
});
const txInfo = {
id: txId,
owner: await arweave.wallets.ownerToAddress(tx.owner),
size: formatBytes(parseInt(tx.data_size)),
reward: `${arweave.ar.winstonToAr(tx.reward)} AR`,
timestamp: new Date().toISOString(), // Approximate
status: status.status === 200 ? 'Confirmed' : `Pending (${status.status})`,
confirmations: status.confirmed?.number_of_confirmations || 0,
blockHeight: status.confirmed?.block_height || 'N/A',
tags,
url: `https://arweave.net/${txId}`
};
if (globalOptions.json) {
output(txInfo, globalOptions);
}
else {
console.log('\nTransaction Information:');
console.log('========================');
console.log(`ID: ${txInfo.id}`);
console.log(`Owner: ${txInfo.owner}`);
console.log(`Size: ${txInfo.size}`);
console.log(`Cost: ${txInfo.reward}`);
console.log(`Status: ${txInfo.status}`);
console.log(`Confirmations: ${txInfo.confirmations}`);
console.log(`Block Height: ${txInfo.blockHeight}`);
console.log(`URL: ${txInfo.url}`);
if (Object.keys(tags).length > 0) {
console.log('\nTags:');
const table = createTable(['Key', 'Value']);
Object.entries(tags).forEach(([key, value]) => {
table.push([key, value]);
});
console.log(table.toString());
}
// Check if this is a bundle transaction
if (tags['Bundle-Format'] && tags['Bundle-Version']) {
console.log('\n📦 This is a bundle transaction!');
console.log('Fetching bundle contents...\n');
try {
const bundleInfo = await fetchAndParseBundle(txId);
console.log(`Bundle contains ${bundleInfo.totalItems} data items:\n`);
const bundleTable = createTable(['#', 'Item ID', 'File Name', 'Size', 'Type']);
bundleInfo.items.forEach((item, index) => {
bundleTable.push([
(index + 1).toString(),
item.id.substring(0, 12) + '...',
item.fileName || 'Unknown',
formatBytes(item.size),
item.contentType || 'Unknown'
]);
});
console.log(bundleTable.toString());
// Show individual item details if verbose
if (globalOptions.verbose) {
console.log('\nDetailed Item Information:');
bundleInfo.items.forEach((item, index) => {
console.log(`\n--- Item ${index + 1} ---`);
console.log(`ID: ${item.id}`);
console.log(`Owner: ${item.owner}`);
console.log(`Size: ${formatBytes(item.size)}`);
if (Object.keys(item.tags).length > 0) {
console.log('Tags:');
Object.entries(item.tags).forEach(([k, v]) => {
console.log(` ${k}: ${v}`);
});
}
});
}
}
catch (bundleError) {
console.log('⚠️ Failed to parse bundle contents:', bundleError instanceof Error ? bundleError.message : String(bundleError));
}
}
}
}
catch (error) {
spinner.stop();
throw error;
}
}));
//# sourceMappingURL=info.js.map