node

package
v0.50.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 28, 2026 License: MIT Imports: 10 Imported by: 0

Documentation

Overview

Package node is the node-authoring seam. A node is a typed Cfg plus a Run function; the framework owns everything else — JSON decode, the result envelope, the assertion/output post-step, and skip handling. Authors write only a Cfg struct (embedding Base) and one Run function, then Register it.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func CodeOf

func CodeOf(err error) string

CodeOf returns a user error's stable code, or "" for a runner fault.

func IsUser

func IsUser(err error) bool

IsUser reports whether err is a user-caused failure (vs a runner fault).

func References

func References(kind spi.Kind) bool

References reports whether a kind's config can implement FlowReferencer (module, ...).

func Register

func Register[Cfg hasBase](kind spi.Kind, fn Run[Cfg])

Register binds a kind to its typed Run. Cfg is inferred from fn; the closure erases it so differently-typed nodes share one registry. Call from an init(). Registering a kind twice panics — that is a wiring bug, caught at load.

func Routes

func Routes(kind spi.Kind) bool

Routes reports whether a kind's config can implement Router (branch, ...).

func UserErrf

func UserErrf(code, format string, args ...any) error

UserErrf builds a coded user error (a spi.UserError) from a formatted message, so echopoint's spi.AsUserError sees new-core failures. Code is a stable string (REQUEST_FAILED, ASSERTION_FAILED, ...); a runner fault is a plain error.

Types

type Base

type Base struct {
	ID         string        `json:"id"`
	Name       string        `json:"display_name"`
	RunWhen    spi.RunWhen   `json:"run_when,omitempty"`
	Assertions []assert.Spec `json:"assertions,omitempty"`
	Outputs    []output.Spec `json:"outputs,omitempty"`
}

Base is embedded by every node Cfg. It carries identity plus the declared assertions and outputs the framework evaluates after the node runs.

type Bound

type Bound struct {
	Base    Base
	Kind    spi.Kind
	Run     func(ctx context.Context, in value.Value, rt Runtime) (Result, error)
	Refs    []string // child flow ids (FlowReferencer), for cycle/existence validation
	Targets []string // route targets (Router), for branch-target validation
}

Bound is a decoded node ready for the engine: its declared Base, its kind, a type-erased run closure holding the typed Cfg, and any capabilities the Cfg opted into (Refs/Targets), surfaced generically for validation.

func Decode

func Decode(kind spi.Kind, raw json.RawMessage) (Bound, error)

Decode turns a raw node definition into a Bound node via the registry.

type Clock

type Clock interface {
	Sleep(ctx context.Context, d time.Duration) error
	Now() time.Time
}

Clock waits and reads wall time, respecting cancellation.

type FlowReferencer

type FlowReferencer interface {
	ReferencedFlows() []string
}

FlowReferencer is implemented by node configs that reference child flows by id (module, ...), so the engine can validate references and detect cycles without special-casing the kind.

type HTTPDoer

type HTTPDoer interface {
	Do(req *http.Request) (*http.Response, error)
}

HTTPDoer performs HTTP requests.

type Result

type Result struct {
	// Outputs are the named values the node produces for downstream nodes.
	Outputs value.Map
	// Assert is the value the node's declared assertions/outputs run against
	// when Provided is true. A provider that asserts over its own Outputs leaves
	// it zero — the engine boxes Outputs once, and only when assertions or
	// outputs are actually declared. Set it only to assert over something else
	// (the assert node targets the whole input context).
	Assert value.Value
	// Provided is set by nodes that expose a value for the framework's uniform
	// assertion/output post-step (request, set_variable, assert, loop). Nodes
	// that evaluate their own assertions (poll, sse) or route (branch) or have
	// none (delay, module) leave it false, and the engine skips the post-step.
	Provided bool
	// Assertions is set by self-evaluating nodes (poll, sse) to surface the
	// assertion outcomes they evaluated internally — the engine records these on
	// the node result, since its post-step (which fills them for provider nodes)
	// does not run for self-evaluating nodes.
	Assertions assert.Results
	// Routed is set by routing nodes (branch): the successor ids execution was
	// routed to. The engine skips every other successor (and its subtree). Nil
	// for ordinary nodes — all successors run.
	Routed []string
}

Result is what a node's Run returns.

type Router

type Router interface {
	RouteTargets() []string
}

Router is implemented by node configs that route to specific successors (branch, ...), so the engine can validate that every target has an edge.

type Run

type Run[Cfg hasBase] func(ctx context.Context, cfg Cfg, in value.Value, rt Runtime) (Result, error)

Run is the node-author function: typed cfg + the node's input context (flow inputs and upstream outputs, accessible by path) + runtime deps, result out. Most nodes ignore in — templating already filled their cfg; assert/branch use it to evaluate over inputs without naming them.

type Runtime

type Runtime struct {
	HTTP    HTTPDoer
	Clock   Clock
	Subflow SubflowRunner
	Vars    spi.DynamicResolver
}

Runtime is the explicit dependency set handed to every node — genuine external effects only, no assert/extract/error sugar. A node touches only the fields it needs; a test builds a Runtime with just those. Vars resolves {{$dyn}} dynamic variables (spi.DynamicResolver, satisfied by pkg/dynamicvars).

type SubflowRunner

type SubflowRunner interface {
	RunSubflow(ctx context.Context, flowID string, in value.Map) (value.Map, error)
	RunInline(ctx context.Context, f flow.Flow, in value.Map) (value.Map, error)
}

SubflowRunner runs child flows and returns their outputs. The engine satisfies this; injecting it (rather than importing the engine) keeps the node package free of an import cycle and lets tests fake it. module references a flow by id; loop/poll run an inline body flow.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL