Skip to content

Node-RED

@onerp/node-red (packages/node-red) is a Node-RED palette for calling into OnERP: reading and writing business object records and invoking operations. It is call-only — OnERP does not push events, so a flow triggers from Node-RED’s own side (inject, cron, MQTT, http in) and then talks to OnERP. Under the hood every node runs on @onerp/client, authenticated with a service-account API key.

The package depends on workspace packages, so a plain npm install <path> cannot resolve it. pnpm deploy materializes a self-contained copy first:

Terminal window
pnpm turbo build --filter=@onerp/node-red
pnpm --filter @onerp/node-red deploy --prod --legacy /tmp/onerp-node-red
cd ~/.node-red && npm install /tmp/onerp-node-red

Restart Node-RED; the three flow nodes appear under the OnERP category.

For working on the package itself, skip the deploy: pnpm --filter @onerp/node-red dev:red starts a local Node-RED on :1880 that loads the nodes straight from the source tree (nodesDir), with its flows kept in a gitignored .node-red/ inside the package. Run pnpm --filter @onerp/node-red dev alongside for the TypeScript watch, and restart Node-RED to pick up a rebuilt node.

Every flow node points at an onerp-config node holding the server’s base URL and an API key. Create the key under Settings → Service Accounts — its role decides what the flows may do. The key is stored in Node-RED’s encrypted credentials store, not in the flow export.

The connection builds its client when the flow deploys: a wrong URL or key fails loudly at deploy time (red node status), not at 3am mid-flow. The workspace’s meta is loaded at the same moment and stays fixed until the next deploy — a domain deployed to the server later is not visible to running flows until Node-RED redeploys.

Identity lives in the editor (business object, mode, operation); data rides the message. Records cross into flows as plain wire JSON — decimals and dates are strings, safe for debug, switch and template nodes.

Mode In Out (msg.payload)
get msg.id the record; null when missing (not an error)
list msg.payload = { filter?, sort?, cursor?, limit?, withTotal? } (optional) { items, nextCursor, total? } — feed nextCursor back as cursor to page on
Mode In Out (msg.payload)
create msg.payload = record the created record
update msg.id + msg.payload = patch the updated record
delete msg.id payload passes through unchanged
Target In Out (msg.payload)
function — Operation = namespace/name, Business Object empty msg.payload = params the result; null when the operation returns nothing
bound action — Business Object set, Operation = action name msg.id + msg.payload = params same

A failed request raises through the node’s error path, so a catch node routes it like any other flow error. When the failure is an OnERP error response, the message additionally carries the structured body:

{ "onerpError": { "code": "core.forbidden", "status": 403, "detail": "…" } }

The node’s status dot mirrors the last outcome — green ok, red with the error code. There are no retries; Node-RED’s own catch/retry patterns apply.