@nextera.one/nestflow-engine-sdk
v1.0.1
Published
SDK for building, testing, and publishing custom NestFlow node engines
Maintainers
Readme
@nextera.one/nestflow-engine-sdk
Official SDK for building, testing, and publishing custom NestFlow node engines.
Installation
npm install @nextera.one/nestflow-engine-sdkPeer dependencies (your project must have these):
npm install @nestjs/common reflect-metadataQuick Start
1. Create a Custom Engine
import { Injectable } from "@nestjs/common";
import {
NodeEngine,
NodeExecutionStrategy,
NodeExecutionContext,
NodeDto,
} from "@nextera.one/nestflow-engine-sdk";
@Injectable()
@NodeEngine("WEATHER_FETCH")
export class WeatherFetchEngine implements NodeExecutionStrategy {
async execute(node: NodeDto, context: NodeExecutionContext): Promise<any> {
const { city } = node.params;
if (!city) {
throw new Error('Parameter "city" is required');
}
// Your custom logic here
const response = await fetch(
`https://api.weatherapi.com/v1/current.json?key=${node.params.apiKey}&q=${city}`,
);
const data = await response.json();
// Store result in flow context for downstream nodes
context._set(context.ctx, `weather.${city}`, data);
return data;
}
}2. Test Your Engine Locally
import {
EngineTestBed,
createMockNode,
} from "@nextera.one/nestflow-engine-sdk/testing";
import { WeatherFetchEngine } from "./weather-fetch.engine";
async function main() {
const engine = new WeatherFetchEngine();
const testBed = new EngineTestBed(engine);
// Verify decorator metadata
console.log("Registered types:", testBed.getRegisteredNodeTypes());
// → ['WEATHER_FETCH']
// Run a single execution
const result = await testBed.execute(
createMockNode({
type: "WEATHER_FETCH",
params: { city: "London", apiKey: "test-key" },
}),
);
console.log("Result:", result);
// Run a batch of test cases
const results = await testBed.runTests([
{
name: "fetches weather for a valid city",
node: createMockNode({
type: "WEATHER_FETCH",
params: { city: "London", apiKey: "test-key" },
}),
},
{
name: "throws error when city is missing",
node: createMockNode({
type: "WEATHER_FETCH",
params: { apiKey: "test-key" },
}),
shouldThrow: true,
errorMessage: "city",
},
]);
testBed.printResults(results);
}
main();3. Multi-Type Engine
A single engine can handle multiple node types:
@Injectable()
@NodeEngine(["MATH_ADD", "MATH_MULTIPLY", "MATH_DIVIDE"])
export class MathEngine implements NodeExecutionStrategy {
async execute(node: NodeDto, context: NodeExecutionContext): Promise<any> {
const { a, b } = node.params;
switch (node.type) {
case "MATH_ADD":
return { result: a + b };
case "MATH_MULTIPLY":
return { result: a * b };
case "MATH_DIVIDE":
if (b === 0) throw new Error("Division by zero");
return { result: a / b };
default:
throw new Error(`Unknown math operation: ${node.type}`);
}
}
}API Reference
Main Exports (@nextera.one/nestflow-engine-sdk)
| Export | Description |
| ----------------------- | --------------------------------------------------- |
| NodeExecutionStrategy | Interface — implement execute(node, context) |
| NodeExecutionContext | Interface — the context passed to your engine |
| NodeDto | Interface — the node data (id, type, params) |
| EdgeDto | Interface — a directed edge (source → target) |
| FlowDefinitionDto | Interface — full flow definition (id, nodes, edges) |
| NodeEngine(type) | Decorator — registers your class for node type(s) |
| NODE_ENGINE_KEY | Metadata key constant |
Testing Exports (@nextera.one/nestflow-engine-sdk/testing)
| Export | Description |
| ----------------------------- | ---------------------------------------- |
| EngineTestBed | Test harness for running engines locally |
| createMockContext(options?) | Creates a mock NodeExecutionContext |
| createMockNode(overrides) | Creates a mock NodeDto |
NodeExecutionContext Properties
| Property | Type | Description |
| ------------------------- | -------------------------- | -------------------------------------------- |
| ctx | any | Mutable flow context shared across all nodes |
| db | any | Database client (Knex on the platform) |
| nodes | Record<string, NodeDto> | All nodes in the flow keyed by ID |
| edges | Record<string, string[]> | Adjacency list (source → targets) |
| fullDef | FlowDefinitionDto | Complete flow definition |
| logger | Logger | Scoped logger (log, error, warn, debug) |
| _get(obj, path) | Function | Get nested property by dot notation |
| _set(obj, path, value) | Function | Set nested property by dot notation |
| encryptRow(table, data) | Function | Encrypt a data row |
| decryptRow(table, row) | Function | Decrypt a data row |
| executeNode(...) | Function | Trigger sub-node execution |
| subscriberService | any | Event emitter service |
| redisService | any | Redis cache service |
| guardRegistry | Record | Flow guards |
| middlewareRegistry | Record | Flow middleware |
| interceptorRegistry | Record | Flow interceptors |
| flowRunnerService | any | Flow runner reference |
EngineTestBed Methods
| Method | Returns | Description |
| ------------------------------------------- | ------------------------------ | ------------------------------------------- |
| execute(node, contextOptions?) | Promise<any> | Run the engine with a node |
| executeWithContext(node, contextOptions?) | Promise<{ result, context }> | Run and return both result and context |
| runTests(testCases) | Promise<TestCaseResult[]> | Run a batch of test cases |
| printResults(results) | boolean | Print results, returns true if all passed |
| getRegisteredNodeTypes() | string[] \| undefined | Get @NodeEngine metadata |
NodeDto Structure
interface NodeDto {
id: string; // Unique node ID
type: string; // Node type (matches @NodeEngine)
params: Record<string, any>; // Engine parameters
position?: { x: number; y: number }; // Canvas position (optional)
data?: Record<string, any>; // Additional metadata (optional)
}Publishing to NestFlow
Once your engine passes all local tests, you can upload it to the NestFlow platform:
- Build your engine project
- Run tests to verify all test cases pass
- Upload via the NestFlow dashboard or CLI
License
MIT
