Closed schellenbergk closed 2 months ago
Hey there! I believe this might have something to do with using Blob from buffer vs the web file api, although most versions of node support this natively. What version of node are you currently running?
v18.18.0... So basically I'm using nextjs api route to upload to pinata and the image file comes from current directory.
When i try Pinata example from docs in my nextjs api route:
const { PinataSDK } = require("pinata")
const fs = require("fs")
const { Blob } = require("buffer")
const pinata = new PinataSDK({
pinataJwt: process.env.PINATA_JWT!,
pinataGateway: "example-gateway.mypinata.cloud"
})
const blob = new Blob([fs.readFileSync("./hello-world.txt")]);
const file = new File([blob], "hello-world.txt", { type: "text/plain"})
const upload = await pinata.upload.file(file);
I'm getting Type 'Blob' is not assignable to type 'BlobPart'.
because the issue here is that Node.js' buffer.Blob is not directly compatible with the Web API's Blob, even though they share a similar API surface.
Gotcha! Couple of things, could you try removing const { Blob } = require("buffer")
from the code and see what that does?
Also just to clarify, are you trying to upload a local file from the next directory or a file that a user selects from their computer? If the latter we have this guide: https://docs.pinata.cloud/web3/frameworks/next-js
Final note, I noticed you might be trying to use IPFS in which case you will want to use the pinata-web3
Alright, some progress, but now ReferenceError: File is not defined
Do you by chance have a repo you could share so I can try to reproduce this?
.env.example
and add JWT & GATEWAY env varsyarn install
yarn dev
http://localhost:3000/api/pinata
to testThanks!! Will get back to you on this
For now, as a workaround I'm using the old SDK:
// THIS WORKS:
import pinataSDK from '@pinata/sdk';
import path from 'path';
import fs from 'fs';
...
const pinata = new pinataSDK({
pinataJWTKey: process.env.IPFS_PINATA_JWT!,
});
const outputDir = path.join(process.cwd(), 'tmp');
const imgPath = path.join(outputDir, `new-image.png`);
const readableStream = fs.createReadStream(imgPath);
const uploadResult = await pinata.pinFileToIPFS(readableStream, {
pinataMetadata: { name: path.basename(imgPath) },
});
const newPhoto = `${process.env.GATEWAY_URL!}${uploadResult.IpfsHash}`;
Oh nice!! I wonder if it's from using a read stream instead of a file object. Could you perhaps expand on the use case of uploading repo file inside Next? Just want to understand better and see if there's a solution we could look into.
Actually I just got it to work as well with the current SDK. I suspected the real issue was with how Next handles local repo files as files you can read. Once I put the file in a tmp folder it worked like a charm
import { PinataSDK } from "pinata-web3";
// import { PinataSDK } from 'pinata';
import { NextApiRequest, NextApiResponse } from "next";
import path from "path";
import fs from "fs";
const handler = async (
req: NextApiRequest,
res: NextApiResponse<boolean | any>,
) => {
try {
const outputDir = path.join(process.cwd(), "tmp");
const filePath = path.join(outputDir, `slapcity.png`);
const pinata = new PinataSDK({
pinataJwt: process.env.IPFS_PINATA_JWT!,
});
const fileBuffer = fs.readFileSync(filePath);
const blob = new Blob([fileBuffer], { type: "image/png" });
const file = new File([blob], path.basename(filePath), {
type: "image/png",
lastModified: new Date().getTime(),
});
// Upload the buffer directly to Pinata
const uploadResult = await pinata.upload.file(file, {
metadata: {
name: "SlapCityNft",
},
});
console.log("Uploaded to Pinata:", uploadResult);
const newPhoto = `${process.env.NEXT_PUBLIC_GATEWAY_URL}${uploadResult.IpfsHash}`;
return res.json({
filePath,
uploadResult,
newPhoto,
});
} catch (e) {
console.log(e);
return res.status(500).json("Error uploading to Pinata");
}
};
export default handler;
Oh nice!! I wonder if it's from using a read stream instead of a file object. Could you perhaps expand on the use case of uploading repo file inside Next? Just want to understand better and see if there's a solution we could look into.
the use case is that I generate a new image in my api route, then upload it to Pinata.
Actually I just got it to work as well with the current SDK. I suspected the real issue was with how Next handles local repo files as files you can read. Once I put the file in a tmp folder it worked like a charm
Are you sure? I just tried it and it did not work... Still getting ReferenceError: File is not defined
...
What's your node version?
Hey @schellenbergk I just cloned your repo and everything worked as expected. I'm on node v20.11.1
I tried on node v18 and it fails with the same error. This is because the File class and the Blob class were introduced in node v20. But you can still upload using the SDK. This works using your existing repo code with a couple of modifications.
import {PinataSDK} from 'pinata-web3';
// import { PinataSDK } from 'pinata';
import {NextApiRequest, NextApiResponse} from 'next';
import path from 'path';
import fs from 'fs';
import { Blob } from "buffer"
const handler = async (
req: NextApiRequest,
res: NextApiResponse<boolean | any>
) => {
try {
const filePath = path.join(process.cwd(), 'assets', 'slapcity.png');
const pinata = new PinataSDK({
pinataJwt: process.env.IPFS_PINATA_JWT!,
});
const fileBuffer = fs.readFileSync(filePath);
// Convert Buffer to Blob
const blob: any = new Blob([fileBuffer], { type: 'image/png' });
// Make sure to handle Pinata SDK correctly; assuming the SDK can accept form data directly
const uploadResult = await pinata.upload.file(blob);
console.log('Uploaded to Pinata:', uploadResult);
const newPhoto = `${process.env.NEXT_PUBLIC_GATEWAY_URL}${uploadResult.IpfsHash}`;
return res.json({
filePath,
uploadResult,
newPhoto,
});
} catch (e) {
console.log(e);
return res.status(500).json('Error uploading to Pinata');
}
};
export default handler;
We'll update the docs to indicate how to do this for node 18 which is still part of LTS.
Perfect, thanks for all your time. Pura Vida!
The problem is with
new File([blob]
, as it complainsType 'Blob' is not assignable to type 'BlobPart'