UNPKG

n8n-nodes-recraft-v3

Version:

Unofficial n8n community node for Recraft v3 AI image generation and editing API - the #1 ranked text-to-image model. Created for testing and community use.

109 lines (108 loc) 4.69 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.validateBinaryData = exports.recraftApiRequest = void 0; const n8n_workflow_1 = require("n8n-workflow"); async function recraftApiRequest(method, resource, body = {}, qs = {}, option = {}, files) { const credentials = await this.getCredentials('recraftApi'); if (!credentials?.apiToken) { throw new n8n_workflow_1.NodeOperationError(this.getNode(), 'No API token found. Please configure your Recraft API credentials.'); } let options = { method, qs, body, url: `https://external.api.recraft.ai/v1${resource}`, headers: { Authorization: `Bearer ${credentials.apiToken}`, }, json: true, timeout: 60000, // 60 second timeout for large image operations }; // Handle file uploads (multipart/form-data) if (files && Object.keys(files).length > 0) { // Use formData for multipart uploads options.formData = { ...body, ...files, }; // Remove conflicting options delete options.body; delete options.json; // Let the request library handle Content-Type with boundary if (options.headers && 'Content-Type' in options.headers) { delete options.headers['Content-Type']; } } // Merge any additional options options = Object.assign({}, options, option); try { const response = await this.helpers.request(options); // Handle full response objects if (options.resolveWithFullResponse === true) { return response.body || response; } return response; } catch (error) { // Enhanced error handling if (error.response?.body) { const errorBody = error.response.body; let errorMessage = 'Recraft API Error'; if (typeof errorBody === 'string') { errorMessage = errorBody; } else if (errorBody.error) { errorMessage = typeof errorBody.error === 'string' ? errorBody.error : errorBody.error.message || 'Unknown API error'; } else if (errorBody.message) { errorMessage = errorBody.message; } throw new n8n_workflow_1.NodeApiError(this.getNode(), error, { message: errorMessage, description: `Recraft API returned an error: ${errorMessage}`, httpCode: error.response.statusCode?.toString(), }); } // Handle network and other errors if (error.code === 'ECONNREFUSED') { throw new n8n_workflow_1.NodeApiError(this.getNode(), error, { message: 'Could not connect to Recraft API', description: 'Please check your internet connection and try again.', }); } if (error.code === 'ETIMEDOUT') { throw new n8n_workflow_1.NodeApiError(this.getNode(), error, { message: 'Request to Recraft API timed out', description: 'The request took too long to complete. Please try again.', }); } throw new n8n_workflow_1.NodeApiError(this.getNode(), error); } } exports.recraftApiRequest = recraftApiRequest; async function validateBinaryData(itemIndex, propertyName) { try { const binaryData = this.helpers.assertBinaryData(itemIndex, propertyName); // Validate file size (5MB limit for Recraft API) const maxSize = 5 * 1024 * 1024; // 5MB in bytes const fileSize = Buffer.byteLength(binaryData.data, 'base64'); if (fileSize > maxSize) { throw new n8n_workflow_1.NodeOperationError(this.getNode(), `File size (${Math.round(fileSize / 1024 / 1024)}MB) exceeds the 5MB limit.`); } // Validate file type const allowedMimeTypes = ['image/png', 'image/jpeg', 'image/jpg', 'image/webp']; if (binaryData.mimeType && !allowedMimeTypes.includes(binaryData.mimeType)) { throw new n8n_workflow_1.NodeOperationError(this.getNode(), `Unsupported file type: ${binaryData.mimeType}. Supported types: PNG, JPEG, WEBP.`); } return binaryData; } catch (error) { if (error.message?.includes('no binary data exists')) { throw new n8n_workflow_1.NodeOperationError(this.getNode(), `No binary data found in property "${propertyName}". Please ensure you've connected a node that provides binary data.`); } throw error; } } exports.validateBinaryData = validateBinaryData;