This document provides a technical reference for defining and managing GLIDE Actions in a typed manner. It covers:
In GLIDE, an Action represents a reusable, typed unit that can be plugged into a workflow step (e.g., a "linear" step). Each action has:
input
(fields with types like string
, number
,
dictionary
, etc.).
output
definition, specifying the result shape produced.
The system uses valibot schemas (InputSchema
, OutputSchema
) to validate
definitions and ensure type consistency at runtime. This means you can rely on correct
shapes when integrating with broader GLIDE workflows.
We maintain distinct definitions for:
InputField
: a single input field from InputFieldSchema
(with type
,
required
, constraints, etc.).
OutputField
: a single output field from OutputFieldSchema
(similar structure, but used
for "what the action outputs").Each type can be:
- string, text, password => TS string
- integer, number => TS number
- boolean => TS boolean
- date => TS string (ISO date)
- duration => TS number (milliseconds or a numeric value)
- file => TS string (file path or URL)
- dictionary => TS Record<string, string>
The InputSchema
and OutputSchema
also support extendable fields, which allow
adding additional custom fields
beyond a base set.
We provide utility types to derive a TypeScript data model from the validated schema. This ensures your
action's handler receives typed input
objects and returns typed output
shapes without
manual duplication.
InferInputShape<TInput>
Given an input definition object (TInput
) that matches InputSchema
,
InferInputShape<TInput>
produces the final structure. It accounts for:
required: true|false
.
extendable: true
, merges them into the shape with their own
required/optional flags.InferOutputShape<TOutput>
Similarly, for an output definition that matches OutputSchema
,
InferOutputShape<TOutput>
yields the final shape of results
your action returns.
This includes required vs. optional output fields, as well as extended fields.
An action handler is the function that executes the logic for your action.
It's typed with StepHandler<TInput, TOutput>
, where:
InferInputShape
of your input definition.InferOutputShape
if your action has an output
definition,
otherwise an empty record ({}
).The handler signature:
type StepHandler<TInput, TOutput> = (
id: string,
input: TInput,
durable: IWorkflowDurableExecutor,
config?: StepConfig,
auth?: AuthType,
extendedPropertyNames?: string[],
abortSignal?: AbortSignal
) => Promise<ActionResult<TOutput>>;
The handler:
id
(the step ID in the workflow) and the input
object typed by your
schema.config
(StepConfigSchema
), auth
(AuthSchema
), and extendedPropertyNames
to see which fields were extended.Promise<ActionResult<TOutput>>
containing results
of type
TOutput
.
An ActionDefinition captures the metadata and logic for an action:
id
(unique name like "my_action"
)version
("v1"
, "v2"
, etc.)inputDefinition
(matching InputSchema
)outputDefinition
(matching OutputSchema
, optional)handler
— the actual function to run with typed input/outputactionBuilder
Utility
The actionBuilder
function streamlines creating an action with full type inference. Usage:
actionBuilder({
id: "my_action",
version: "v1",
input: { /* input schema object */ },
output: { /* output schema object */ },
}).implement((id, input, durable, config, auth, extendedProps) => {
// 1) do work with input
// 2) return results
return { results: { /* shape matches your output definition */ } };
});
We maintain a dynamic registry (actionRegistry
) for actions. You can:
registerAction(key, definition)
: Validates the inputDefinition
and
outputDefinition
against valibot schemas, then stores it in a Map
under key
.
getActionDefinition(key)
: Retrieves the ActionDefinition
if one is registered under
key
.
getActionHandler(key)
: Retrieves just the handler function if needed.getListOfActions()
: Returns an array of all registered action keys.
Registering an action ensures the DSL definitions are validated once. If the same key
is used twice, an
error is thrown.
// 1) Define a minimal input schema (no extended fields)
const myInput = {
extendable: false,
fields: {
username: {
label: "User",
help: "User name",
type: "string",
required: true,
value: "DefaultUser",
}
}
};
// 2) Build the action
const myAction = actionBuilder({
id: "my_action",
version: "v1",
input: myInput
}).implement(async (id, input, durable) => {
// input is { username: string }
console.log("Hello,", input.username);
return {};
});
// 3) Register it
registerAction("my_action@v1", myAction);
// Suppose we define an output schema with some fields
const myOutput = {
extendable: false,
fields: {
greeting: {
label: "Greeting",
help: "Generated greeting text",
type: "string",
required: true
},
timestamp: {
label: "Timestamp",
help: "Time of generation",
type: "date",
required: false
}
}
};
const greetInput = {
extendable: false,
fields: {
name: {
label: "Name",
help: "Whom to greet",
type: "string",
required: true,
value: "World"
}
}
};
const greetAction = actionBuilder({
id: "greet",
version: "v1",
input: greetInput,
output: myOutput
}).implement(async (id, input, durable) => {
// input => { name: string }
const greeting = `Hello, ${input.name}!`;
// We must return an object matching the output definition shape
return {
results: {
greeting, // required
timestamp: new Date().toISOString() // optional
}
};
});
// Register into the global action registry
registerAction("greet@v1", greetAction);
const handler = getActionHandler("greet@v1");
if (handler) {
// We can call it with dynamic input
handler("some_step_id", { name: "Alice" }, someDurableExecutor)
.then((result) => console.log(result));
}
Potential errors and their causes:
registerAction
,
if inputDefinition
or outputDefinition
fails valibot checks, an error is thrown
immediately.key
(e.g.
"greet@v1"
) multiple times,
registerAction
throws an error.
handler
function, anything from network failures to
logic bugs can throw.
Those are not handled by the registry directly. The calling code must handle or await the promise from
handler
.
Reference | Description | Link |
---|---|---|
actions.ts | Implementation of ActionDefinition , builder, registry, etc. |
View Code |