No estoy seguro de si esto es posible, pero esto es lo que estoy tratando de hacer:
ReadStreamLogré lograr (1) y (2) usando html2canvas .
La parte difícil es (3). La razón por la que tiene que estar en formato ReadStream es porque ese es el formato que quiere el SDK de Pinata :
const fs = require('fs'); const readableStreamForFile = fs.createReadStream('./yourfile.png'); const options = { pinataMetadata: { name: MyCustomName, keyvalues: { customKey: 'customValue', customKey2: 'customValue2' } }, pinataOptions: { cidVersion: 0 } }; pinata.pinFileToIPFS(readableStreamForFile, options).then((result) => { //handle results here console.log(result); }).catch((err) => { //handle error here console.log(err); });Me doy cuenta de que no sería un problema hacerlo en el backend con el nodo, pero me gustaría hacerlo en el front-end. ¿Es eso posible? ¿O estoy loco?
Estoy usando específicamente Vue si eso importa.
Para cualquier persona interesada, la solución terminó siendo usar fetch+blob:
const generateImg = async () => { const canvas = await html2canvas(document.getElementById('hello')); const img = canvas.toDataURL('image/png'); const res = await fetch(img); return res.blob(); };Este blob se puede pasar a una versión más manual de su SDK:
const uploadImg = (blob: Blob) => { const url = `https://api.pinata.cloud/pinning/pinFileToIPFS`; const data = new FormData(); data.append('file', blob); const metadata = JSON.stringify({ name: 'testname', }); data.append('pinataMetadata', metadata); const pinataOptions = JSON.stringify({ cidVersion: 0, }); data.append('pinataOptions', pinataOptions); return axios .post(url, data, { maxBodyLength: 'Infinity' as any, // this is needed to prevent axios from erroring out with large files headers: { // @ts-ignore 'Content-Type': `multipart/form-data; boundary=${data._boundary}`, pinata_api_key: apiKey, pinata_secret_api_key: apiSecret, }, }) .then((response) => { console.log(response); }) .catch((error) => { console.log(error); }); };