A flow is a canvas tab: a saved layout of source, transform, and sink nodes. The engine
runs each source as an async polling task; each record is routed through its transform,
then fans out to the configured sink set. Events are passed as native
CanonicalMachineData structs, never re-serialized at the DSL boundary, which is why
the DSL is so fast.
Per-source routing
Transforms are addressed by {source}:{machine.id}. A record looks up its own route
first, then falls back to default. Each route carries its own script and its own
sink set, so one source can drop noisy machines, enrich others, and push to different
backends:
transform:
enabled: true
default:
backend: "dsl"
script_inline: "set metadata.processedAt = timestamp"
sinks: ["storage", "push"]
sources:
- key: "http:ERP-01"
backend: "js"
script: "./transforms/erp.js"
sinks: ["nats", "clickhouse"]