This guide will help you create your own node for the Deforge system. Please follow all instructions carefully to ensure compatibility and maintainability.
Use the snippet node to generate a boiler plate for your node. This will generate a boilerplate which leverages typescript types to provide better type hinting while writing the code.
Every node must extend the BaseNode class (imported from ../../core/BaseNode/node.js) and implement the run() method.
import BaseNode from "../../core/BaseNode/node.js";
class my_node extends BaseNode {
constructor() {
super(config);
}
// ...
async run(inputs, contents, webconsole, serverData) {
}
}Each node file must define a config object at the top, following the format below (see BaseNode/node.js for reference):
const config = {
title: "Node Title",
category: "category_folder_name",
type: "node_class_name", // should match the folder name
icon: {
type: "svg/jpeg/png",
content: "base64 of the image"
},
desc: "Optional node description",
credits: 0, // Amount of deforge credits to be used by the node
inputs: [
{ name: "Name", type: "NodeType", desc: "" },
],
outputs: [
{ name: "Name", type: "NodeType", desc: "" },
],
fields: [
{ name: "fieldOnNode", type: "HTML input type", desc: "", value: "placeholder value" },
],
difficulty: "easy/medium/hard",
tags: ["tag1", "tag2"],
}Each node's run method receives inputs and contents arrays. To get a value, you should prioritize inputs over contents. Here is a recommended pattern:
const SomeValue = (inputs.find(e => e.name === "SomeField")?.value)
|| (contents.find(e => e.name === "SomeField")?.value)
|| "default value";Example from another node:
const Link = inputs.find(e => e.name === "Link")?.value
|| contents.find(e => e.name === "Link")?.value
|| "";You can access some information passed on from the server via the serverData object. The object contains the following data:
serverData: {
workflowId: workflowId,
envList: envList,
socialList: socialList,
chatId: chatId,
redisUtil: redisUtil
refreshUtil: refreshUtil
},workflowId: ID of the workflow being executed, that is calling the given node.envList: A key-value pair list of env variables for the given workflow.socialList: A key-value pair list of the social accounts and access tokens for the connected accounts in the given workflow.chatId: A chat or user ID of the user executing the workflow. (Must be passed as achatIdquery via the deployment url)redisUtil: An utility class that contains three methods:setKey,deleteKeyandgetKeythat can be used to store data in redis. (Key format:deforge:subcontext:task. Example:deforge:twitter:cookies)refreshUtil: An utility to update refreshed oauth tokens in the database.
Return an object with output names as keys:
return { "Output Name": outputValue };Example:
return { "Video Link": uploadedUrl };If your node can fail, return null.
Use the webconsole object for logging. It has three methods:
webconsole.success(...args)webconsole.info(...args)webconsole.error(...args)
You can pass as many parameters as you want to these methods. Example:
webconsole.info("Starting download", url);
webconsole.success("Upload complete", resultUrl);
webconsole.error("Failed to process", error.message);Each node is self-contained. You must install all required npm packages for each node inside that node's folder (where its package.json is located). For example, if your node uses axios, run:
cd path/to/your/node_folder
npm install axiosimport BaseNode from "../../core/BaseNode/node.js";
const config = { /* ...see above... */ };
class my_node extends BaseNode {
constructor() {
super(config);
}
async run(inputs, contents, webconsole, serverData) {
const Field = inputs.find(e => e.name === "Field")?.value
|| contents.find(e => e.name === "Field")?.value
|| "default";
webconsole.info("Processing field", Field);
// ... your logic ...
return { "Output": result };
}
}
export default my_node;For more examples, see other nodes in the repository. Always follow this structure for compatibility with the Deforge system.
Application to test your own nodes visually will be available soon...