CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-node-red

Low-code programming platform for event-driven applications with visual flow-based editor and runtime system

Pending
Quality

Pending

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

SecuritybySnyk

Pending

The risk profile of this skill

Overview
Eval results
Files

function-nodes.mddocs/

Function Nodes

JavaScript execution environment and APIs available within Node-RED Function nodes. Function nodes provide a secure sandbox for running custom JavaScript code with access to Node-RED's messaging system and context storage.

Capabilities

Function Node Context

Global objects and APIs available in the Function node execution environment.

/**
 * Available in Function node context
 */
interface FunctionNodeGlobals {
    /** Current message being processed */
    msg: NodeMessage;
    /** Node instance with control methods */
    node: NodeInstance;
    /** Node-scoped persistent storage */
    context: ContextStore;
    /** Flow-scoped persistent storage */
    flow: ContextStore;
    /** Global-scoped persistent storage */
    global: ContextStore;
    /** Environment variables access */
    env: EnvironmentVariables;
    /** Node-RED utilities subset */
    RED: NodeREDUtilities;
}

/**
 * Message object structure
 */
interface NodeMessage {
    /** Unique message identifier */
    _msgid: string;
    /** Message topic (optional) */
    topic?: string;
    /** Message payload (any type) */
    payload: any;
    /** Additional message properties */
    [key: string]: any;
}

Basic Function Node Example:

// Simple message transformation
msg.payload = msg.payload.toString().toUpperCase();
msg.timestamp = Date.now();
return msg;

// Multiple outputs
if (msg.payload > 10) {
    return [msg, null]; // Send to first output only
} else {
    return [null, msg]; // Send to second output only
}

// Multiple messages to same output
return [
    [
        { payload: "First message" },
        { payload: "Second message" }
    ],
    null
];

Node Instance Methods

Methods available on the node object for controlling node behavior and output.

/**
 * Node instance methods
 */
interface NodeInstance {
    send(msg: NodeMessage | NodeMessage[], clone?: boolean): void;
    error(err: string | Error, msg?: NodeMessage): void;
    warn(warning: string | object): void;
    log(info: string | object): void;
    status(status: NodeStatus | string | boolean | number): void;
    done(err?: Error): void;
}

/**
 * Send message(s) to connected nodes
 * @param msg - Message or array of messages to send
 * @param clone - Whether to clone messages before sending (default: true)
 */
node.send(msg: NodeMessage | NodeMessage[], clone?: boolean): void;

/**
 * Log error and trigger catch nodes
 * @param err - Error message or Error object
 * @param msg - Optional message that caused the error
 */
node.error(err: string | Error, msg?: NodeMessage): void;

/**
 * Log warning message
 * @param warning - Warning message or object
 */
node.warn(warning: string | object): void;

/**
 * Log informational message
 * @param info - Info message or object
 */
node.log(info: string | object): void;

/**
 * Set node status indicator
 * @param status - Status object, string, boolean, or number
 */
node.status(status: NodeStatus | string | boolean | number): void;

Usage Examples:

// Send processed message
msg.payload = processData(msg.payload);
node.send(msg);

// Send without cloning (more efficient but potentially unsafe)
node.send(msg, false);

// Error handling
try {
    msg.payload = JSON.parse(msg.payload);
    node.send(msg);
} catch (err) {
    node.error("Invalid JSON in payload", msg);
}

// Status updates
node.status({ fill: "blue", shape: "ring", text: "processing..." });
// Clear status
node.status({});

// Logging
node.log(`Processing message with topic: ${msg.topic}`);
node.warn("Deprecated feature used");

Context Storage

Persistent storage system available at node, flow, and global scopes.

/**
 * Context storage interface
 */
interface ContextStore {
    get(key: string, callback?: (err: Error, value: any) => void): any;
    get(keys: string[], callback?: (err: Error, values: any[]) => void): any[];
    set(key: string, value: any, callback?: (err: Error) => void): void;
    set(keys: string[], values: any[], callback?: (err: Error) => void): void;
    keys(callback?: (err: Error, keys: string[]) => void): string[];
}

/**
 * Get value from context (synchronous)
 * @param key - Context key or array of keys
 * @returns Value or array of values
 */
context.get(key: string | string[]): any;

/**
 * Get value from context (asynchronous)
 * @param key - Context key or array of keys
 * @param callback - Callback function
 */
context.get(key: string | string[], callback: (err: Error, value: any) => void): void;

/**
 * Set value in context
 * @param key - Context key or array of keys
 * @param value - Value to store or array of values
 * @param callback - Optional callback function
 */
context.set(key: string | string[], value: any, callback?: (err: Error) => void): void;

/**
 * Get all context keys
 * @param callback - Optional callback function
 * @returns Array of keys (if synchronous)
 */
context.keys(callback?: (err: Error, keys: string[]) => void): string[];

Context Storage Examples:

// Node-scoped storage (persists across messages for this node)
const counter = context.get("counter") || 0;
context.set("counter", counter + 1);

// Flow-scoped storage (shared across all nodes in this flow)
const flowData = flow.get("sharedData") || {};
flowData.lastUpdate = Date.now();
flow.set("sharedData", flowData);

// Global storage (shared across all flows)
const globalConfig = global.get("config") || {};

// Store selection with specific store
const value = context.get("key", "file"); // Get from file store
context.set("key", "value", "memory"); // Set in memory store

// Asynchronous operations
context.get("asyncKey", (err, value) => {
    if (!err) {
        node.log(`Retrieved: ${value}`);
    }
});

// Multiple keys
const values = context.get(["key1", "key2", "key3"]);
context.set(["key1", "key2"], ["value1", "value2"]);

// Get all keys
const allKeys = context.keys();

Environment Variables

Access to environment variables and Node-RED predefined variables.

/**
 * Environment variables interface
 */
interface EnvironmentVariables {
    get(name: string): string | undefined;
}

/**
 * Get environment variable
 * @param name - Environment variable name
 * @returns Environment variable value or undefined
 */
env.get(name: string): string | undefined;

Predefined Environment Variables:

  • NR_NODE_ID - Current node ID
  • NR_NODE_NAME - Current node name
  • NR_NODE_PATH - Current node path
  • NR_GROUP_ID - Parent group ID (if in group)
  • NR_GROUP_NAME - Parent group name (if in group)
  • NR_FLOW_ID - Current flow ID
  • NR_FLOW_NAME - Current flow name
  • NR_SUBFLOW_ID - Subflow instance ID (if in subflow)
  • NR_SUBFLOW_NAME - Subflow name (if in subflow)
  • NR_SUBFLOW_PATH - Subflow path (if in subflow)

Usage Examples:

// System environment variables
const dbHost = env.get("DATABASE_HOST") || "localhost";
const apiKey = env.get("API_KEY");

// Node-RED predefined variables
const nodeId = env.get("NR_NODE_ID");
const nodeName = env.get("NR_NODE_NAME") || "Unnamed";
const flowName = env.get("NR_FLOW_NAME");

// Use in logging
node.log(`Node ${nodeName} (${nodeId}) in flow ${flowName} processing message`);

// Conditional logic based on environment
if (env.get("NODE_ENV") === "development") {
    node.log("Debug info:", msg);
}

Node-RED Utilities

Subset of Node-RED utilities available in Function nodes.

/**
 * Node-RED utilities available in Function nodes
 */
interface NodeREDUtilities {
    util: {
        generateId(): string;
        cloneMessage(msg: NodeMessage): NodeMessage;
        setMessageProperty(msg: NodeMessage, prop: string, value: any): boolean;
        getMessageProperty(msg: NodeMessage, prop: string): any;
    };
}

/**
 * Generate unique identifier
 * @returns Generated ID string
 */
RED.util.generateId(): string;

/**
 * Clone message object safely
 * @param msg - Message to clone
 * @returns Cloned message
 */
RED.util.cloneMessage(msg: NodeMessage): NodeMessage;

/**
 * Set property on message using dot notation
 * @param msg - Target message object
 * @param prop - Property path (e.g., "payload.data.value")
 * @param value - Value to set
 * @returns true if successful
 */
RED.util.setMessageProperty(msg: NodeMessage, prop: string, value: any): boolean;

/**
 * Get property from message using dot notation
 * @param msg - Source message object
 * @param prop - Property path (e.g., "payload.data.value")
 * @returns Property value
 */
RED.util.getMessageProperty(msg: NodeMessage, prop: string): any;

Usage Examples:

// Generate IDs for tracking
const requestId = RED.util.generateId();
msg.requestId = requestId;

// Safe message cloning
const backup = RED.util.cloneMessage(msg);

// Dynamic property access
const sensorValue = RED.util.getMessageProperty(msg, "payload.sensors.temperature");
RED.util.setMessageProperty(msg, "payload.processed.timestamp", Date.now());

// Complex property paths
const path = "payload.data.items.0.value";
const value = RED.util.getMessageProperty(msg, path);
if (value !== undefined) {
    RED.util.setMessageProperty(msg, "payload.firstItemValue", value);
}

Advanced Patterns

Asynchronous Operations

// Using callbacks with context
context.get("config", (err, config) => {
    if (err) {
        node.error("Failed to get config", msg);
        return;
    }
    
    msg.payload = processWithConfig(msg.payload, config);
    node.send(msg);
});

// Using setTimeout for delays
setTimeout(() => {
    msg.payload = "Delayed message";
    node.send(msg);
}, 5000);

Multiple Output Handling

// Route messages based on conditions
const route1 = [];
const route2 = [];

msg.payload.forEach(item => {
    if (item.type === "urgent") {
        route1.push({ payload: item });
    } else {
        route2.push({ payload: item });
    }
});

// Send arrays of messages to different outputs
node.send([route1, route2]);

Error Handling Patterns

try {
    // Risky operation
    const result = JSON.parse(msg.payload);
    msg.payload = result;
    node.send(msg);
} catch (err) {
    // Send error to catch node
    node.error(err.message, msg);
    // Or handle gracefully
    node.warn("Invalid JSON, using default");
    msg.payload = {};
    node.send(msg);
}

Types

interface NodeStatus {
    fill?: 'red' | 'green' | 'yellow' | 'blue' | 'grey';
    shape?: 'ring' | 'dot';
    text?: string;
}

interface NodeMessage {
    _msgid: string;
    topic?: string;
    payload: any;
    [key: string]: any;
}

docs

application.md

cli.md

function-nodes.md

http-services.md

index.md

node-development.md

runtime.md

utilities.md

tile.json