UNPKG

@coinbase/agentkit

Version:

Coinbase AgentKit core primitives

217 lines (216 loc) 7.99 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.generateTokenUri = void 0; const fs_1 = __importDefault(require("fs")); const path_1 = __importDefault(require("path")); /** * Reads a local file and converts it to base64 * * @param imageFileName - Path to the local file * @returns Base64 encoded file and mime type */ async function readFileAsBase64(imageFileName) { return new Promise((resolve, reject) => { fs_1.default.readFile(imageFileName, (err, data) => { if (err) { reject(new Error(`Failed to read file: ${err.message}`)); return; } // Determine mime type based on file extension const extension = path_1.default.extname(imageFileName).toLowerCase(); let mimeType = "application/octet-stream"; // default if (extension === ".png") mimeType = "image/png"; else if (extension === ".jpg" || extension === ".jpeg") mimeType = "image/jpeg"; else if (extension === ".gif") mimeType = "image/gif"; else if (extension === ".svg") mimeType = "image/svg+xml"; const base64 = data.toString("base64"); resolve({ base64, mimeType }); }); }); } /** * Uploads a base64 image to IPFS using Flaunch API * Rate Limit: Maximum 4 image uploads per minute per IP address * * @param params - Configuration and base64 image data * @param params.base64Image - Base64 encoded image data * @param params.name - Optional name for the uploaded file * @param params.metadata - Optional metadata key-value pairs * @returns Upload response with CID and other details */ const uploadImageToIPFS = async (params) => { try { const response = await fetch("https://web2-api.flaunch.gg/api/v1/upload-image", { method: "POST", headers: { "Content-Type": "application/json", }, body: JSON.stringify({ base64Image: params.base64Image }), }); if (!response.ok) { const error = await response.json(); throw new Error(`Failed to upload image to IPFS: ${error.message || response.statusText}`); } const data = await response.json(); if (!data.success) { throw new Error(`Failed to upload image to IPFS: ${data.error || "Unknown error"}`); } return { IpfsHash: data.ipfsHash, tokenURI: data.tokenURI, }; } catch (error) { if (error instanceof Error) { throw new Error(`Failed to upload image to IPFS: ${error.message}`); } throw error; } }; /** * Uploads JSON data to IPFS using Flaunch API * * @param params - Configuration and JSON data * @param params.json - JSON data to upload * @param params.name - Optional name for the uploaded file * @param params.metadata - Optional metadata key-value pairs * @returns Upload response with CID and other details */ const uploadJsonToIPFS = async (params) => { try { const response = await fetch("https://web2-api.flaunch.gg/api/v1/upload-metadata", { method: "POST", headers: { "Content-Type": "application/json", }, body: JSON.stringify({ name: params.json.name, symbol: params.json.symbol, description: params.json.description, imageIpfs: params.json.image, websiteUrl: params.json.external_link, discordUrl: params.json.discordUrl, twitterUrl: params.json.twitterUrl, telegramUrl: params.json.telegramUrl, }), }); if (!response.ok) { const error = await response.json(); throw new Error(`Failed to upload JSON to IPFS: ${error.message || response.statusText}`); } const data = await response.json(); if (!data.success) { throw new Error(`Failed to upload metadata: ${data.error}`); } return { IpfsHash: data.ipfsHash, tokenURI: data.tokenURI, }; } catch (error) { if (error instanceof Error) { throw new Error(`Failed to upload JSON to IPFS: ${error.message}`); } throw error; } }; /** * Converts a remote image URL to a properly formatted base64 data URL * * @param imageUrl - URL of the image to fetch and convert * @returns Base64 data URL with proper MIME type detection */ const convertImageUrlToBase64 = async (imageUrl) => { try { const response = await fetch(imageUrl); if (!response.ok) { throw new Error(`Failed to fetch image: ${response.statusText}`); } const arrayBuffer = await response.arrayBuffer(); const base64Data = Buffer.from(arrayBuffer).toString("base64"); // Detect MIME type from response headers const contentType = response.headers.get("content-type"); let mimeType = "image/jpeg"; // default fallback if (contentType && contentType.startsWith("image/")) { mimeType = contentType; } else { // Try to detect from URL extension as fallback const urlLower = imageUrl.toLowerCase(); if (urlLower.includes(".png")) { mimeType = "image/png"; } else if (urlLower.includes(".gif")) { mimeType = "image/gif"; } else if (urlLower.includes(".webp")) { mimeType = "image/webp"; } else if (urlLower.includes(".svg")) { mimeType = "image/svg+xml"; } } return `data:${mimeType};base64,${base64Data}`; } catch (error) { if (error instanceof Error) { throw new Error(`Failed to convert image URL to base64: ${error.message}`); } throw error; } }; const generateTokenUriBase64Image = async (name, symbol, params) => { // 1. upload image to IPFS const imageRes = await uploadImageToIPFS({ base64Image: params.metadata.base64Image, }); // 2. upload metadata to IPFS const coinMetadata = { name, symbol, description: params.metadata.description, image: `ipfs://${imageRes.IpfsHash}`, external_link: params.metadata.websiteUrl || "", collaborators: [], discordUrl: params.metadata.discordUrl || "", twitterUrl: params.metadata.twitterUrl || "", telegramUrl: params.metadata.telegramUrl || "", }; const metadataRes = await uploadJsonToIPFS({ json: coinMetadata, }); return `ipfs://${metadataRes.IpfsHash}`; }; const generateTokenUri = async (name, symbol, params) => { // 1. get base64Image from image (url or local path) let base64Image; const image = params.metadata.image; if (image.startsWith("https://") || image.startsWith("http://")) { base64Image = await convertImageUrlToBase64(image); } else { // assume local file const { base64, mimeType } = await readFileAsBase64(image); base64Image = `data:${mimeType};base64,${base64}`; } // 2. generate token uri const tokenUri = await generateTokenUriBase64Image(name, symbol, { metadata: { base64Image, description: params.metadata.description, websiteUrl: params.metadata.websiteUrl, discordUrl: params.metadata.discordUrl, twitterUrl: params.metadata.twitterUrl, telegramUrl: params.metadata.telegramUrl, }, }); return tokenUri; }; exports.generateTokenUri = generateTokenUri;