TypeScript SDK (@industream/flowmaker-sdk)
Package: sdk/typescript.
Overview
The TypeScript SDK provides the runtime infrastructure for building FlowBox workers—stateless or stateful components that process data streams in the FlowMaker platform.
[INFO!hub/SDK SCOPE] This SDK handles the runtime loop, serialization, and logging. Your FlowBox implementations focus on business logic: transforming data, calling external APIs, or managing state.
Documentation Index
Getting Started
Implementation Guides
- FlowBox Implementations (Source, Pipe, Sink) — How to build each node type
- FlowBoxLogger API — Logging and socket management
- FlowBoxSerializer API — Serialization and headers
Runtime Architecture & Data Flow
[NOTE!lightbulb/DIAGRAM CONTEXT] This diagram shows a typical three-stage pipeline. Data flows down (Source → Pipe → Sink) via ZMQ frames with headers. Logs flow right to the Logger via Socket.IO. Control events flow to the Scheduler via ZMQ.
How data flows:
- Source initiates data by calling
onOutputReady(), pushing{ val, $$meta, $$timestamp }with a MessagePack header - Pipe receives via
onInputReceived(), transforms, and pushes downstream with the same header format - Sink receives final data, processes it (e.g., saves to database), and acknowledges
- Logger receives log events via Socket.IO (dashed lines), displays in the frontend
- Scheduler manages lifecycle (init, destroy, heartbeat) via ZMQ control events (dotted lines)
Data Shape Convention
All FlowBox integrations should use this standard data shape for compatibility with DataCatalog and metadata-aware processing:
{
"temperature": 21.7,
"pressure": 1.8,
"$$meta": {
"temperature": { "entryId": "dc-entry-temp" },
"pressure": { "entryId": "dc-entry-pressure" }
},
"$$timestamp": "2026-04-10T16:00:00.000Z"
}
$$meta: Per-field metadata (e.g., DataCatalog entry references)$$timestamp: ISO 8601 timestamp of data creation
[NOTE!lightbulb/META PROPERTY CONTRACT] The
$$metaobject must have field names as keys matching the data properties. Mismatched keys will cause DataCatalog auto-fetchers to skip enrichment.
[WARNING!shield/RESERVED PREFIX] Properties starting with
$$are reserved for runtime metadata. Do not use this prefix for application data—it may be overwritten or stripped by SDK components.
Quick Start
A minimal worker entrypoint:
// src/index.ts
import { FlowBoxEventLoopHandler, FlowBoxFactory } from "@industream/flowmaker-sdk";
import { MyPipe } from "./my-pipe";
const handler = new FlowBoxEventLoopHandler(
process.env.FM_ROUTER_TRANSPORT_ADDRESS || 'tcp://*:5560',
process.env.FM_RUNTIME_HTTP_ADDRESS || 'http://localhost:3100',
new FlowBoxFactory([MyPipe])
);
await handler.run();
A minimal pipe implementation:
// src/my-pipe.ts
import { FlowBoxCore, FlowBoxRegistration, flowBoxSerializer } from "@industream/flowmaker-sdk";
@FlowBoxRegistration({
id: "myorg/my-pipe",
displayName: "My Pipe",
currentVersion: "1.0.0",
type: "pipe",
icon: "transform",
stateless: true,
agent: "flowmaker-node/1.0.0",
workerId: process.env.FM_WORKER_ID!,
workerDataConnectionString: process.env.FM_WORKER_TRANSPORT_ADV_ADDRESS!,
ioInterfaces: {
inputs: [{ name: "input", supportedFormats: ["msgpack"] }],
outputs: [{ name: "output", supportedFormats: ["msgpack"] }]
},
uiConfig: { defaultOptions: {}, implementation: null }
})
export class MyPipe extends FlowBoxCore {
protected async onInput(inputId: Buffer, header: Buffer, data: Buffer): Promise<void> {
const input = flowBoxSerializer.unpack(header, data);
await this.push("output", flowBoxSerializer.pack(header, { ...input, processed: true }), header);
}
}
[INFO!info/RUNTIME INITIALIZATION] The
run()method starts an infinite async dispatch loop. The process won't exit naturally—use SIGINT/SIGTERM for shutdown.
Build Commands
From sdk/typescript:
pnpm install
pnpm build