JavaScript
Inline JavaScript executed by the kernel. JavaScript.Script is a Telo.Invocable for per-request compute that is too complex for a CEL expression but does not warrant a dedicated controller.
Why use this
- Invocable anywhere — usable from HTTP handlers, sequence steps, workflow nodes, or any invocable slot.
- Typed inputs and outputs —
inputType/outputTypeaccept inline JSON Schema or a namedType.JsonSchema; the runtime validates inputs beforemainruns. - Async-aware —
mainmay beasync; the kernel awaits the return value. - Structured errors — thrown
Errors surface through the normalRun.Sequencetry/catchflow.
Kinds
| Kind | Purpose |
|---|---|
JavaScript.Script | Run an inline main({ ... }) JavaScript function as an invocable resource. |
Example
kind: JavaScript.Script
metadata:
name: Add
inputType:
type: object
properties:
a: { type: number }
b: { type: number }
required: [a, b]
outputType:
type: object
properties:
sum: { type: number }
code: |
function main({ a, b }) {
return { sum: a + b };
}
The script contract
The code field must define a main function. The kernel calls it with the invocation inputs and uses the returned value as the result.
mainmay beasync— the kernel awaits its return.- The returned value is the full result; property access (
result.sum) works downstream. - Throwing an
Errorsurfaces as an invocation error through the normalRun.Sequencetry/catchflow.
Typed inputs and outputs
inputType and outputType accept either an inline JSON Schema or a named Type.JsonSchema reference. They drive analyzer validation and the editor's autocomplete — the runtime itself also validates inputs before main runs.
kind: Type.JsonSchema
metadata:
name: Email
schema:
type: object
properties:
email: { type: string }
required: [email]
---
kind: JavaScript.Script
metadata:
name: Normalize
inputType: Email
code: |
function main({ email }) {
return { normalized: email.trim().toLowerCase() };
}
Using it in a sequence
kind: Run.Sequence
metadata:
name: PriceItem
steps:
- name: compute
invoke:
kind: JavaScript.Script
inputs:
quantity: "${{ inputs.quantity }}"
unitPrice: "${{ inputs.unitPrice }}"
code: |
function main({ quantity, unitPrice }) {
const net = quantity * unitPrice;
return { net, gross: net * 1.23 };
}
outputs:
total: "${{ steps.compute.result.gross }}"
Notes
- The Node.js controller compiles
codevianew Function. Scripts run in the host's global scope — they are not sandboxed. TreatJavaScript.Scriptas application code, not a trust boundary. requireand ESMimportare not available (the code is aFunctionbody, not a module).process,Buffer, and other globals are reachable if needed.- Scripts are compiled once at resource creation and reused across invocations, so avoid per-call top-level work — put state setup inside
mainif it depends on inputs. - For heavier logic (third-party libraries, typed models, shared helpers) write a dedicated controller package instead.