Observability Utilities
Hydrate step I/O, parse display names, and decrypt workflow data using workflow/observability.
The workflow/observability module provides utilities for working with workflow data in observability and debugging tools. It includes functions to hydrate serialized step I/O, parse machine-readable names into display-friendly formats, and decrypt encrypted workflow data.
Import
import {
hydrateResourceIO,
observabilityRevivers,
parseStepName,
parseWorkflowName,
parseClassName,
} from "workflow/observability"; Data Hydration
hydrateResourceIO()
Deserialize step or run data that was serialized using the devalue format. This is required to display step input/output in your UI.
import { hydrateResourceIO, observabilityRevivers } from "workflow/observability";
import { getWorld } from "workflow/runtime";
const world = getWorld();
const step = await world.steps.get(runId, stepId);
const hydrated = hydrateResourceIO(step, observabilityRevivers);
console.log(hydrated.input); // Deserialized input data
console.log(hydrated.output); // Deserialized output dataParameters:
| Parameter | Type | Description |
|---|---|---|
resource | Step | WorkflowRun | The step or run with serialized data |
revivers | Revivers | Reviver functions for deserialization. Use observabilityRevivers for standard use. |
Returns: The resource with hydrated input and output fields.
observabilityRevivers
A set of reviver functions that handle standard workflow serialization types (Date, Map, Set, Error, etc.).
import { observabilityRevivers } from "workflow/observability";Name Parsing
Workflow and step names are stored as machine-readable identifiers. These utilities extract display-friendly names.
parseStepName()
Parse a machine-readable step name into its components.
import { parseStepName } from "workflow/observability";
const parsed = parseStepName("step//./src/workflows/order//processPayment");
// parsed.shortName → "processPayment"
// parsed.moduleSpecifier → "./src/workflows/order"Parameters:
| Parameter | Type | Description |
|---|---|---|
stepName | string | The machine-readable step name |
Returns: { shortName: string, moduleSpecifier: string } | null
parseWorkflowName()
Parse a machine-readable workflow name into its components.
import { parseWorkflowName } from "workflow/observability";
const parsed = parseWorkflowName("workflow//./src/workflows/order//processOrder");
// parsed.shortName → "processOrder"
// parsed.moduleSpecifier → "./src/workflows/order"Parameters:
| Parameter | Type | Description |
|---|---|---|
workflowName | string | The machine-readable workflow name |
Returns: { shortName: string, moduleSpecifier: string } | null
parseClassName()
Parse a machine-readable class name into its components.
import { parseClassName } from "workflow/observability";
const parsed = parseClassName("class//./src/models//User");
// parsed.shortName → "User"
// parsed.moduleSpecifier → "./src/models"Parameters:
| Parameter | Type | Description |
|---|---|---|
className | string | The machine-readable class name |
Returns: { shortName: string, moduleSpecifier: string } | null
Encryption
For workflows with encrypted step data, use these utilities to decrypt before hydrating.
getEncryptionKeyForRun()
Retrieve the encryption key used for a specific workflow run.
import { getEncryptionKeyForRun } from "workflow/observability";
const key = await getEncryptionKeyForRun(runId); Parameters:
| Parameter | Type | Description |
|---|---|---|
runId | string | The workflow run ID |
Returns: Encryption key for the run
hydrateResourceIOWithKey()
Hydrate step or run data using a decryption key. Use this instead of hydrateResourceIO() when data is encrypted.
import {
getEncryptionKeyForRun,
hydrateResourceIOWithKey,
} from "workflow/observability";
const key = await getEncryptionKeyForRun(runId);
const hydrated = hydrateResourceIOWithKey(step, key); Parameters:
| Parameter | Type | Description |
|---|---|---|
resource | Step | WorkflowRun | The step or run with encrypted serialized data |
key | EncryptionKey | The encryption key from getEncryptionKeyForRun() |
Returns: The resource with decrypted and hydrated input and output fields.
Examples
Hydrate Step Input and Output Data
import { getWorld } from "workflow/runtime";
import {
hydrateResourceIO,
observabilityRevivers,
parseStepName,
} from "workflow/observability";
export async function GET(req: Request) {
const url = new URL(req.url);
const runId = url.searchParams.get("runId");
const stepId = url.searchParams.get("stepId");
if (!runId || !stepId) {
return Response.json({ error: "runId and stepId required" }, { status: 400 });
}
const world = getWorld();
const step = await world.steps.get(runId, stepId);
const hydrated = hydrateResourceIO(step, observabilityRevivers);
const parsed = parseStepName(step.stepName);
return Response.json({
displayName: parsed?.shortName ?? step.stepName,
input: hydrated.input,
output: hydrated.output,
});
}Decrypt and Hydrate Encrypted Step Data
For teams with encryption enabled, step data must be decrypted before hydration:
import { getWorld } from "workflow/runtime";
import {
getEncryptionKeyForRun,
hydrateResourceIOWithKey,
parseStepName,
} from "workflow/observability";
export async function GET(req: Request) {
const url = new URL(req.url);
const runId = url.searchParams.get("runId");
const stepId = url.searchParams.get("stepId");
if (!runId || !stepId) {
return Response.json({ error: "runId and stepId required" }, { status: 400 });
}
const world = getWorld();
const step = await world.steps.get(runId, stepId);
// Decrypt then hydrate
const key = await getEncryptionKeyForRun(runId);
const hydrated = hydrateResourceIOWithKey(step, key);
const parsed = parseStepName(step.stepName);
return Response.json({
displayName: parsed?.shortName ?? step.stepName,
input: hydrated.input,
output: hydrated.output,
});
}Parse Display Names for a Run's Steps
Build a progress dashboard with human-readable step names:
import { getWorld } from "workflow/runtime";
import { parseStepName, parseWorkflowName } from "workflow/observability";
const world = getWorld();
// Parse workflow name
const run = await world.runs.get(runId, { resolveData: "none" });
const workflowDisplay = parseWorkflowName(run.workflowName);
console.log("Workflow:", workflowDisplay?.shortName);
// Parse step names
const steps = await world.steps.list({ runId, resolveData: "none" });
for (const step of steps.data) {
const stepDisplay = parseStepName(step.stepName);
console.log(` ${stepDisplay?.shortName}: ${step.status}`);
}Related
- world.steps — Query step data to hydrate
- world.runs — Query run data to hydrate
- Serialization — How workflow data is serialized