figma-image-handler.ts•3.28 kB
import { z } from "zod/v3";
import axios from "axios";
import {
logger,
FigmaServerError,
ErrorType,
createErrorResponse,
withTimeout,
} from "../utils/error-handling.js";
import { getFigmaFileKeyAndNodeId } from "../utils/figma-utils.js";
import type { FigmaApiClient } from "../api/figma-client.js";
/**
* Tool definition for fetching Figma node image by file key and node ID
*/
export const fetchFigmaNodeImageTool = {
name: "fetch_figma_node_image",
description:
"Fetches a PNG image of a Figma node or frame using the file key and node ID. Returns the image as base64.",
inputSchema: {
fileKey: z.string().describe("The key of the Figma file to fetch, Can be found in a provided URL like `figma.com/(file|design)/<fileKey>/..."),
nodeId: z.string().describe("The ID of the node to fetch, can be found as URL parameter like `node-id=<nodeId>`, Must use if provided."),
},
} as const;
/**
* Fetches an image from Figma and converts it to base64.
*/
async function fetchImageFromFigma(
figmaClient: FigmaApiClient,
fileKey: string,
nodeId: string,
operation: string
) {
logger.debug("Making API request to get image", { fileKey, nodeId });
const imageResponse = await figmaClient.getImages(fileKey, nodeId, "png");
const nodeIdTransformed = figmaClient.transformNodeId(nodeId);
const imageUrl =
imageResponse.images[nodeId] || imageResponse.images[nodeIdTransformed];
if (!imageUrl) {
throw new FigmaServerError(
`No image found for node ID ${nodeId} in Figma file ${fileKey}.`,
ErrorType.NOT_FOUND,
{
operation,
fileKey,
nodeId,
timestamp: new Date().toISOString(),
},
404
);
}
logger.debug("Downloading image from URL", { imageUrl });
const imageResponseData = await withTimeout(
axios.get(imageUrl, {
responseType: "arraybuffer",
}),
60000,
`${operation}-download`
);
const image = Buffer.from(imageResponseData.data, "binary").toString(
"base64"
);
logger.info("Successfully fetched and converted image to base64", {
fileKey,
nodeId,
imageSizeKB: Math.round((image.length * 0.75) / 1024),
});
return {
content: [
{
type: "image" as const,
data: image,
alt: `Image for node ID ${nodeId} in Figma file ${fileKey}`,
mimeType: "image/png",
},
],
};
}
/**
* Handler function for fetching Figma node image by file key and node ID.
*/
export const fetchFigmaNodeImageHandler = async (
figmaClient: FigmaApiClient,
{ fileKey, nodeId }: { fileKey: string; nodeId: string }
) => {
try {
logger.info("Fetching image by file key and node ID", { fileKey, nodeId });
if (!fileKey || !nodeId) {
throw new FigmaServerError(
"Invalid input. Please provide both file key and node ID.",
ErrorType.VALIDATION_ERROR,
{
operation: "fetchFigmaNodeImage",
input: { fileKey, nodeId },
timestamp: new Date().toISOString(),
},
400
);
}
return await fetchImageFromFigma(
figmaClient,
fileKey,
nodeId,
"fetchFigmaNodeImage"
);
} catch (error) {
return createErrorResponse(error as Error, "fetchFigmaNodeImage");
}
};