@bernierllc/temporal-workflow-ui
Version:
Thin domain-specific wrapper around @bernierllc/generic-workflow-ui for Temporal workflows
168 lines (166 loc) • 5.21 kB
JavaScript
;
/*
Copyright (c) 2025 Bernier LLC
This file is licensed to the client under a limited-use license.
The client may use and modify this code *only within the scope of the project it was delivered for*.
Redistribution or use in other products or commercial offerings is not permitted without written consent from Bernier LLC.
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.jsonToTemporalWorkflow = jsonToTemporalWorkflow;
/**
* Convert JSON definition (n8n-style) to Temporal workflow
*
* @param json - JSON workflow definition
* @returns Temporal workflow
*/
function jsonToTemporalWorkflow(json) {
const stages = json.nodes.map((node, index) => jsonNodeToTemporalStage(node, index));
const transitions = buildTransitionsFromConnections(json.connections);
const staticData = json.staticData || {};
return {
id: json.meta?.instanceId || generateId(),
name: json.name,
description: json.nodes[0]?.notes,
stages,
transitions,
metadata: {},
defaultTaskQueue: staticData.defaultTaskQueue,
workflowTimeout: staticData.workflowTimeout,
searchAttributes: staticData.searchAttributes,
};
}
/**
* Convert JSON node to Temporal stage
*
* @param node - JSON workflow node
* @param index - Node index for order
* @returns Temporal workflow stage
*/
function jsonNodeToTemporalStage(node, index) {
const nodeData = node.data || {};
const temporalMetadata = nodeData.temporal;
// Validate node type is a valid Temporal node type
if (!isValidTemporalNodeType(node.type)) {
throw new Error(`Invalid Temporal node type: ${node.type}`);
}
// If no temporal metadata, create default based on type
const metadata = temporalMetadata || createDefaultMetadata(node.type);
return {
id: node.id,
name: node.name,
description: node.notes,
order: index,
type: node.type,
metadata,
icon: nodeData.icon,
color: nodeData.color,
};
}
/**
* Build transitions from connections object
*
* @param connections - Workflow connections
* @returns Array of Temporal transitions
*/
function buildTransitionsFromConnections(connections) {
const transitions = [];
for (const [fromId, outputs] of Object.entries(connections)) {
for (const [, connectionArrays] of Object.entries(outputs)) {
for (const connectionArray of connectionArrays) {
for (const connection of connectionArray) {
const transitionId = `${fromId}-${connection.node}`;
const connectionData = connection.data || {};
transitions.push({
id: transitionId,
from: fromId,
to: connection.node,
name: connectionData.name,
description: connectionData.description,
condition: connectionData.condition,
metadata: connectionData.metadata,
});
}
}
}
}
return transitions;
}
/**
* Check if a string is a valid Temporal node type
*
* @param type - Type string to validate
* @returns True if valid
*/
function isValidTemporalNodeType(type) {
const validTypes = [
'activity',
'agent',
'signal',
'trigger',
'child-workflow',
'parallel',
'condition',
];
return validTypes.includes(type);
}
/**
* Create default metadata for a node type
*
* @param type - Node type
* @returns Default metadata
*/
function createDefaultMetadata(type) {
switch (type) {
case 'activity':
return {
nodeType: 'activity',
activityName: 'defaultActivity',
taskQueue: 'default',
};
case 'agent':
return {
nodeType: 'agent',
agentPromptId: 'default-prompt',
agentName: 'Default Agent',
taskQueue: 'default',
};
case 'signal':
return {
nodeType: 'signal',
signalName: 'defaultSignal',
};
case 'trigger':
return {
nodeType: 'trigger',
triggerType: 'manual',
};
case 'child-workflow':
return {
nodeType: 'child-workflow',
workflowName: 'defaultChildWorkflow',
taskQueue: 'default',
};
case 'parallel':
return {
nodeType: 'parallel',
branches: [],
};
case 'condition':
return {
nodeType: 'condition',
expression: 'true',
trueBranch: '',
falseBranch: '',
};
default:
throw new Error(`Unsupported node type: ${type}`);
}
}
/**
* Generate a unique ID
*
* @returns Unique ID string
*/
function generateId() {
return `temporal-${Date.now()}-${Math.random().toString(36).substring(2, 9)}`;
}