Low-code programming platform for event-driven applications with visual flow-based editor and runtime system
—
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Pending
The risk profile of this skill
General-purpose utilities provided by Node-RED for message handling, logging, event management, and development tasks. These utilities are available both in embedding applications and within Node-RED's execution environment.
Comprehensive logging system with multiple levels and configurable handlers.
/**
* Logging API
*/
interface LoggingAPI {
init(settings: object): void;
addHandler(handler: LogHandler): void;
removeHandler(handler: LogHandler): void;
log(level: string, msg: any): void;
info(msg: any): void;
warn(msg: any): void;
error(msg: any): void;
debug(msg: any): void;
trace(msg: any): void;
audit(event: AuditEvent, req?: http.IncomingMessage): void;
metric(): boolean;
}
/**
* Log info message
* @param msg - Message to log (string or object)
*/
RED.log.info(msg: any): void;
/**
* Log warning message
* @param msg - Warning message to log
*/
RED.log.warn(msg: any): void;
/**
* Log error message
* @param msg - Error message to log
*/
RED.log.error(msg: any): void;
/**
* Log debug message
* @param msg - Debug message to log
*/
RED.log.debug(msg: any): void;
/**
* Log audit event
* @param event - Audit event object
* @param req - Optional HTTP request object
*/
RED.log.audit(event: AuditEvent, req?: http.IncomingMessage): void;Usage Examples:
const RED = require("node-red");
// Basic logging
RED.log.info("Application started");
RED.log.warn("Configuration file not found, using defaults");
RED.log.error("Database connection failed");
// Logging objects
RED.log.debug({ nodeId: "abc123", message: "Processing started" });
// Audit logging
RED.log.audit({
event: "flows.deploy",
level: 20,
user: { username: "admin" },
path: "/flows"
});Utilities for manipulating Node-RED message objects safely and efficiently.
/**
* Message utility functions
*/
interface MessageUtilities {
generateId(): string;
ensureString(value: any): string;
ensureBuffer(value: any): Buffer;
cloneMessage(msg: NodeMessage): NodeMessage;
compareObjects(obj1: any, obj2: any): boolean;
getMessageProperty(msg: NodeMessage, prop: string): any;
setMessageProperty(msg: NodeMessage, prop: string, value: any, createMissing?: boolean): boolean;
getObjectProperty(obj: object, expr: string): any;
setObjectProperty(obj: object, expr: string, value: any, createMissing?: boolean): boolean;
normalisePropertyExpression(str: string, msg?: NodeMessage, toString?: boolean): string[] | string;
normaliseNodeTypeName(name: string): string;
encodeObject(msg: any, opts?: EncodeOptions): any;
getSetting(node: NodeObject, name: string, flow?: FlowObject): string;
}
/**
* Generate a pseudo-unique identifier (8 random hex bytes)
* @returns Generated 16-character hex identifier string
*/
RED.util.generateId(): string;
/**
* Safely clone a Node-RED message object
* @param msg - Message object to clone
* @returns Deep cloned message object
*/
RED.util.cloneMessage(msg: NodeMessage): NodeMessage;
/**
* Get property from message object using dot notation
* @param msg - Message object
* @param prop - Property path (e.g., "payload.data.value")
* @returns Property value or undefined
*/
RED.util.getMessageProperty(msg: NodeMessage, prop: string): any;
/**
* Set property on message object using dot notation
* @param msg - Message object
* @param prop - Property path (e.g., "payload.data.value")
* @param value - Value to set
* @param createMissing - Whether to create missing intermediate objects
* @returns true if property was set successfully
*/
RED.util.setMessageProperty(msg: NodeMessage, prop: string, value: any, createMissing?: boolean): boolean;
/**
* Get property from any object using dot notation
* @param obj - Object to get property from
* @param expr - Property expression (e.g., "data.items[0].name")
* @returns Property value or undefined
*/
RED.util.getObjectProperty(obj: object, expr: string): any;
/**
* Set property on any object using dot notation
* @param obj - Object to set property on
* @param expr - Property expression (e.g., "data.items[0].name")
* @param value - Value to set
* @param createMissing - Whether to create missing intermediate objects
* @returns true if property was set successfully
*/
RED.util.setObjectProperty(obj: object, expr: string, value: any, createMissing?: boolean): boolean;
/**
* Parse and normalize property expressions
* @param str - Property expression string
* @param msg - Optional message object for cross-references
* @param toString - Whether to return as normalized string
* @returns Array of property path segments or normalized string
*/
RED.util.normalisePropertyExpression(str: string, msg?: NodeMessage, toString?: boolean): string[] | string;
/**
* Normalize node type name to camelCase
* @param name - Raw node type name
* @returns Normalized camelCase name
*/
RED.util.normaliseNodeTypeName(name: string): string;
/**
* Encode object for debugging/transmission
* @param msg - Object to encode
* @param opts - Optional encoding options
* @returns Encoded object with type information
*/
RED.util.encodeObject(msg: any, opts?: EncodeOptions): any;
/**
* Get environment variable or node setting
* @param node - Node object for context
* @param name - Setting/environment variable name
* @param flow - Optional flow object for context
* @returns Setting value or empty string if not found
*/
RED.util.getSetting(node: NodeObject, name: string, flow?: FlowObject): string;Usage Examples:
const RED = require("node-red");
// Generate unique IDs
const nodeId = RED.util.generateId(); // Returns 16-character hex string
const sessionId = RED.util.generateId(); // All IDs are same length
// Clone messages safely
const originalMsg = { payload: { data: [1, 2, 3] }, topic: "test" };
const clonedMsg = RED.util.cloneMessage(originalMsg);
// Get nested properties
const value = RED.util.getMessageProperty(originalMsg, "payload.data.0"); // returns 1
// Set nested properties
RED.util.setMessageProperty(clonedMsg, "payload.metadata.timestamp", Date.now(), true);
// Type conversion
const str = RED.util.ensureString(123); // "123"
const buf = RED.util.ensureBuffer("hello"); // Buffer.from("hello")
// Object property manipulation
const obj = { data: { items: [{ name: "test" }] } };
const name = RED.util.getObjectProperty(obj, "data.items[0].name"); // "test"
RED.util.setObjectProperty(obj, "data.items[0].id", 123, true);
// Property expression parsing
const segments = RED.util.normalisePropertyExpression("data.items[0].name"); // ["data", "items", 0, "name"]
// Node type normalization
const normalized = RED.util.normaliseNodeTypeName("My Custom Node"); // "myCustomNode"
// Environment variables and node settings
const nodeId = RED.util.getSetting(node, "NR_NODE_ID"); // Gets the node's ID
const customVar = RED.util.getSetting(node, "MY_CUSTOM_VAR"); // Gets environment variableAdvanced property evaluation system for dynamic value resolution.
/**
* Evaluate node property based on type
* @param value - Property value
* @param type - Property type ('str', 'num', 'bool', 'json', 'msg', 'flow', 'global', 'env', etc.)
* @param node - Node object for context
* @param msg - Message object for context
* @returns Evaluated value
*/
RED.util.evaluateNodeProperty(value: any, type: string, node: NodeObject, msg: NodeMessage): any;
/**
* Parse context store string
* @param str - Context store string (e.g., "#:(file)::key")
* @returns Parsed context store information
*/
RED.util.parseContextStore(str: string): ContextStoreInfo;
/**
* Normalize property expression to array
* @param str - Property expression string
* @returns Array of property path segments
*/
RED.util.normalisePropertyExpression(str: string): string[];Usage Examples:
// Evaluate different property types
const strValue = RED.util.evaluateNodeProperty("hello", "str", node, msg); // "hello"
const msgValue = RED.util.evaluateNodeProperty("payload", "msg", node, msg); // msg.payload
const numValue = RED.util.evaluateNodeProperty("42", "num", node, msg); // 42
const boolValue = RED.util.evaluateNodeProperty("true", "bool", node, msg); // true
// Parse context store references
const storeInfo = RED.util.parseContextStore("#:(file)::myKey");
// Returns: { key: "myKey", store: "file" }Utilities for working with JSONata expressions in Node-RED.
/**
* Prepare JSONata expression with Node-RED functions
* @param value - JSONata expression string
* @param node - Node object for context
* @returns Prepared JSONata expression object
*/
RED.util.prepareJSONataExpression(value: string, node: NodeObject): JSONataExpression;
/**
* Evaluate prepared JSONata expression
* @param expr - Prepared JSONata expression
* @param msg - Message object for evaluation context
* @param callback - Callback function for async evaluation (required)
* @returns void (result returned via callback)
*/
RED.util.evaluateJSONataExpression(expr: JSONataExpression, msg: NodeMessage, callback: Function): void;Node-RED's event emitter for runtime events and inter-component communication.
/**
* Global event emitter
*/
interface EventsAPI extends EventEmitter {
on(event: string, listener: Function): this;
emit(event: string, ...args: any[]): boolean;
removeListener(event: string, listener: Function): this;
removeAllListeners(event?: string): this;
}
/**
* Listen for runtime events
* @param event - Event name
* @param listener - Event handler function
*/
RED.events.on(event: string, listener: Function): void;
/**
* Emit runtime event
* @param event - Event name
* @param args - Event arguments
*/
RED.events.emit(event: string, ...args: any[]): boolean;Common Events:
// Listen for node events
RED.events.on("nodes-started", () => {
console.log("All nodes have started");
});
RED.events.on("nodes-stopped", () => {
console.log("All nodes have stopped");
});
// Flow deployment events
RED.events.on("runtime-event", (event) => {
if (event.id === "runtime-deploy") {
console.log("Flows deployed");
}
});Extensible hook system for intercepting and modifying Node-RED operations.
/**
* Hook management API
*/
interface HooksAPI {
add(type: string, handler: Function): void;
remove(type: string, handler: Function): void;
clear(type: string): void;
trigger(type: string, data: any, callback?: Function): any;
has(type: string): boolean;
}
/**
* Add hook handler
* @param type - Hook type
* @param handler - Hook handler function
*/
RED.hooks.add(type: string, handler: Function): void;
/**
* Remove hook handler
* @param type - Hook type
* @param handler - Hook handler function to remove
*/
RED.hooks.remove(type: string, handler: Function): void;
/**
* Trigger hook execution
* @param type - Hook type
* @param data - Data to pass to hooks
* @param callback - Optional callback for async hooks
*/
RED.hooks.trigger(type: string, data: any, callback?: Function): any;Available Hook Types:
onSend - Before message is sent from nodepreRoute - Before message is routed to next nodespreDeliver - Before message is delivered to nodepostDeliver - After message is delivered to nodeonReceive - When node receives messagepostReceive - After node processes messageonComplete - When message processing completespreInstall - Before node module installationpostInstall - After node module installationpreUninstall - Before node module uninstallationpostUninstall - After node module uninstallationUsage Examples:
// Add message logging hook
RED.hooks.add("onSend", (sendEvents) => {
sendEvents.forEach(event => {
console.log(`Node ${event.source.id} sending:`, event.msg.payload);
});
});
// Add message transformation hook
RED.hooks.add("preDeliver", (event, done) => {
// Add timestamp to all messages
event.msg.timestamp = Date.now();
done();
});interface NodeMessage {
_msgid: string;
topic?: string;
payload: any;
[key: string]: any;
}
interface NodeObject {
id: string;
type: string;
name?: string;
[key: string]: any;
}
interface AuditEvent {
event: string;
level: number;
user?: UserObject;
path?: string;
timestamp?: number;
[key: string]: any;
}
interface LogHandler {
(settings: object): {
log: (level: string, msg: any) => void;
close?: () => void;
};
}
interface ContextStoreInfo {
key: string;
store?: string;
}
interface JSONataExpression {
evaluate(input: any, bindings?: object): any;
assign(name: string, value: any): void;
}
interface EncodeOptions {
maxLength?: number;
}
interface FlowObject {
getSetting(name: string): string;
[key: string]: any;
}