GLIDE Actions Technical Reference Manual

This document provides a technical reference for defining and managing GLIDE Actions in a typed manner. It covers:


Table of Contents

  1. 1. Introduction
  2. 2. Field Type Distinctions
  3. 3. Shape Inference
  4. 4. Handler & ActionResult
  5. 5. Action Definition & Builder
  6. 6. Action Registry
  7. 7. Usage Examples
  8. 8. Error Handling
  9. 9. References

1. Introduction

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:

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.


2. Field Type Distinctions

We maintain distinct definitions for:

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.


3. Shape Inference

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.

3.1 InferInputShape<TInput>

Given an input definition object (TInput) that matches InputSchema, InferInputShape<TInput> produces the final structure. It accounts for:

3.2 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.


4. Handler & ActionResult

An action handler is the function that executes the logic for your action. It's typed with StepHandler<TInput, TOutput>, where:

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:


5. Action Definition & Builder

An ActionDefinition captures the metadata and logic for an action:

5.1 actionBuilder 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 */ } };
});

6. Action Registry

We maintain a dynamic registry (actionRegistry) for actions. You can:

Registering an action ensures the DSL definitions are validated once. If the same key is used twice, an error is thrown.


7. Usage Examples

7.1 Minimal Action with No Output

// 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);

7.2 Action with Output Fields

// 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);

7.3 Retrieving Handlers at Runtime

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)); }

8. Error Handling

Potential errors and their causes:


9. References

Reference Description Link
actions.ts Implementation of ActionDefinition, builder, registry, etc. View Code
End of Manual
For more examples, see additional docs in the main repository.