four-flap-meme-sdk
Version:
SDK for Flap bonding curve and four.meme TokenManager
107 lines (106 loc) • 3.94 kB
JavaScript
export class PinataClient {
constructor(cfg) {
this.ready = (async () => {
const mod = await import('pinata');
this.client = new mod.PinataSDK({ pinataJwt: cfg.jwt, pinataGateway: cfg.gateway });
})();
}
async uploadFile(file) {
await this.ready;
const r = await this.client.upload.file(file);
return { cid: r.cid, id: r.id };
}
async uploadJSON(obj, name = 'meta.json') {
const blob = new Blob([JSON.stringify(obj)], { type: 'application/json' });
const file = new File([blob], name, { type: 'application/json' });
return await this.uploadFile(file);
}
async get(cid) {
await this.ready;
const data = await this.client.gateways.public.get(cid);
return data;
}
async url(cid) {
await this.ready;
return await this.client.gateways.convert(cid);
}
}
/**
* 使用 Pinata JWT 直接上传文件(Node 环境)
* @param jwt Pinata JWT(以 Bearer 形式传入)
* @param filePath 本地文件绝对/相对路径(优先)
* @param data 可选:内存 Buffer(当未提供 filePath 时使用)
* @param fileName 可选:内存数据的文件名
*/
export async function pinFileToIPFSWithJWT(jwt, filePath, data, fileName) {
const axiosMod = await import('axios');
const FormDataMod = await import('form-data');
const fsMod = await import('fs');
const form = new FormDataMod.default ? new FormDataMod.default() : new FormDataMod();
if (filePath && filePath.length > 0) {
form.append('file', fsMod.createReadStream(filePath));
}
else if (data) {
form.append('file', data, { filename: fileName || 'upload.bin' });
}
else {
throw new Error('pinFileToIPFSWithJWT: either filePath or data must be provided');
}
const resp = await axiosMod.default.post('https://api.pinata.cloud/pinning/pinFileToIPFS', form, {
headers: { Authorization: `Bearer ${jwt}`, ...(form.getHeaders ? form.getHeaders() : {}) },
maxContentLength: Infinity,
maxBodyLength: Infinity
});
const d = resp.data || {};
return {
cid: d.IpfsHash || d.cid,
size: d.PinSize,
timestamp: d.Timestamp,
raw: d
};
}
/**
* 便捷方法:上传本地图片路径(返回 CID)
*/
export async function pinImageByPath(jwt, filePath) {
const r = await pinFileToIPFSWithJWT(jwt, filePath);
return r.cid;
}
// ============ 浏览器端(前端)便捷方法 ===========
// 说明:使用浏览器自带 FormData + fetch;参数为 File/Blob 或 dataURL
export async function pinFileToIPFSWithJWTWeb(jwt, file, fileName) {
const form = new FormData();
const name = fileName || file.name || 'upload.bin';
form.append('file', file, name);
const resp = await fetch('https://api.pinata.cloud/pinning/pinFileToIPFS', {
method: 'POST',
headers: { Authorization: `Bearer ${jwt}` },
body: form
});
if (!resp.ok) {
const txt = await resp.text();
throw new Error(`Pinata upload failed: ${resp.status} ${txt}`);
}
const d = await resp.json();
return {
cid: d.IpfsHash || d.cid,
size: d.PinSize,
timestamp: d.Timestamp,
raw: d
};
}
export function dataURLToBlob(dataUrl) {
const [header, base64] = dataUrl.split(',');
const mimeMatch = /data:(.*?);base64/.exec(header || '');
const mime = mimeMatch ? mimeMatch[1] : 'application/octet-stream';
const bin = atob(base64);
const len = bin.length;
const bytes = new Uint8Array(len);
for (let i = 0; i < len; i++)
bytes[i] = bin.charCodeAt(i);
return new Blob([bytes], { type: mime });
}
export async function pinDataURLWithJWTWeb(jwt, dataUrl, fileName = 'image.png') {
const blob = dataURLToBlob(dataUrl);
return await pinFileToIPFSWithJWTWeb(jwt, blob, fileName);
}