UNPKG

@wttp/site

Version:

Web3 Transfer Protocol (WTTP) - Site Contracts and deployment tools

167 lines • 6.86 kB
import fs from "fs"; import path from "path"; import Arweave from "arweave"; import { saveManifest, loadManifest } from "./generateManifest"; /** * Upload files marked for Arweave storage to Arweave using official Arweave library * Updates the manifest with actual Arweave transaction IDs * * @param manifestPath Path to the manifest file (will be updated in place) * @param options Upload options including wallet and source path * @returns Upload result with TXIDs */ export async function uploadToArweave(manifestPath, options = {}) { const { walletPath, wallet, sourcePath, uploadManifest = false } = options; // Load manifest if (!fs.existsSync(manifestPath)) { throw new Error(`Manifest file not found: ${manifestPath}`); } const manifest = loadManifest(manifestPath); // Determine source path const baseSourcePath = sourcePath || path.dirname(manifestPath); // Initialize Arweave const arweave = Arweave.init({ host: "arweave.net", port: 443, protocol: "https", }); // Load wallet let walletKey; if (wallet) { walletKey = wallet; } else if (walletPath) { if (!fs.existsSync(walletPath)) { throw new Error(`Arweave wallet file not found: ${walletPath}`); } walletKey = JSON.parse(fs.readFileSync(walletPath, "utf-8")); } else { throw new Error("Either walletPath or wallet must be provided"); } console.log(`šŸ“¦ Starting Arweave upload for manifest: ${manifestPath}`); console.log(`šŸ“ Source directory: ${baseSourcePath}`); // Find files marked for Arweave storage const arweaveFiles = manifest.siteData.files.filter((file) => file.externalStorage === "arweave"); if (arweaveFiles.length === 0) { console.log(`ā„¹ļø No files marked for Arweave storage in manifest`); return { filesUploaded: 0, filesSkipped: 0, txIds: new Map(), }; } console.log(`šŸ“„ Found ${arweaveFiles.length} files to upload to Arweave`); const txIds = new Map(); let filesUploaded = 0; let filesSkipped = 0; // Upload each file for (let i = 0; i < arweaveFiles.length; i++) { const file = arweaveFiles[i]; // Check if already has a TXID (from previous upload) const currentLocation = file.redirect?.location || ""; const existingTxId = currentLocation.replace(/^ar:\/\//, "").replace(/^arweave:\/\//, ""); if (existingTxId && existingTxId !== "[pending]" && existingTxId.length === 43) { // Valid Arweave TXID format (43 characters base64url) console.log(`ā­ļø Skipping ${file.path} - already has TXID: ${existingTxId}`); txIds.set(file.path, existingTxId); filesSkipped++; continue; } // Resolve file path const fileRelativePath = file.path.replace(/^\.\//, ""); const fileAbsolutePath = path.join(baseSourcePath, fileRelativePath); if (!fs.existsSync(fileAbsolutePath)) { console.warn(`āš ļø File not found: ${fileAbsolutePath} - skipping`); continue; } console.log(`\nšŸ“¤ Uploading ${i + 1}/${arweaveFiles.length}: ${file.path}`); console.log(` Type: ${file.type}, Size: ${file.size} bytes`); try { // Read file data const fileData = fs.readFileSync(fileAbsolutePath); // Create transaction const transaction = await arweave.createTransaction({ data: fileData, }); // Add tags transaction.addTag("Content-Type", file.type); transaction.addTag("File-Path", file.path); if (file.charset) { transaction.addTag("Charset", file.charset); } // Sign transaction await arweave.transactions.sign(transaction, walletKey); // Post transaction const uploader = await arweave.transactions.getUploader(transaction); while (!uploader.isComplete) { await uploader.uploadChunk(); console.log(` šŸ“¤ Upload progress: ${uploader.pctComplete}%`); } const txId = transaction.id; console.log(` āœ… Uploaded! TXID: ${txId}`); // Update manifest if (!file.redirect) { file.redirect = { code: 301, location: `ar://${txId}`, }; } else { file.redirect.location = `ar://${txId}`; } file.status = "uploaded"; txIds.set(file.path, txId); filesUploaded++; // Save manifest after each upload (in case of interruption) saveManifest(manifest, manifestPath); } catch (error) { console.error(` āŒ Failed to upload ${file.path}:`, error); file.status = "error"; throw error; } } // Save updated manifest saveManifest(manifest, manifestPath); console.log(`\nāœ… Arweave upload complete!`); console.log(` Files uploaded: ${filesUploaded}`); console.log(` Files skipped: ${filesSkipped}`); let manifestTxId; // Optionally upload the manifest itself if (uploadManifest) { console.log(`\nšŸ“¤ Uploading manifest to Arweave...`); try { const manifestData = JSON.stringify(manifest, null, 2); const manifestBuffer = Buffer.from(manifestData, "utf-8"); // Create transaction for manifest const manifestTransaction = await arweave.createTransaction({ data: manifestBuffer, }); // Add tags manifestTransaction.addTag("Content-Type", "application/json"); manifestTransaction.addTag("Manifest-Name", manifest.name); manifestTransaction.addTag("Protocol", "wttp"); // Sign transaction await arweave.transactions.sign(manifestTransaction, walletKey); // Post transaction const manifestUploader = await arweave.transactions.getUploader(manifestTransaction); while (!manifestUploader.isComplete) { await manifestUploader.uploadChunk(); console.log(` šŸ“¤ Upload progress: ${manifestUploader.pctComplete}%`); } manifestTxId = manifestTransaction.id; console.log(` āœ… Manifest uploaded! TXID: ${manifestTxId}`); } catch (error) { console.error(` āŒ Failed to upload manifest:`, error); } } return { filesUploaded, filesSkipped, txIds, manifestTxId, }; } //# sourceMappingURL=uploadToArweave.js.map