import { randomUUID } from 'node:crypto' import type { WorkflowNode, WorkflowPort } from './workflows.ts' import type { NodeRef, PortSelector } from './workflow-builder-types.ts' export function defaultPorts(): WorkflowPort[] { return [ { id: randomUUID(), dir: 'in', type: 'default' }, { id: randomUUID(), dir: 'out', type: 'default' }, ] } export function inOnly(): WorkflowPort[] { return [{ id: randomUUID(), dir: 'in', type: 'default' }] } export function resolveNodeId(ref: NodeRef): string { return typeof ref === 'string' ? ref : ref.id } export function resolveSourcePort(node: WorkflowNode, selector?: PortSelector): string { if (!selector) { const port = node.ports?.find(port => port.dir === 'out' && port.type === 'default') if (!port) throw new Error(`No default output port on node '${node.name}' (${node.id})`) return port.id } if (selector === 'subgraph') { const port = node.ports?.find(port => port.dir === 'out' && port.type === 'subgraph') if (!port) throw new Error(`No subgraph port on node '${node.name}' (${node.id})`) return port.id } const input = node.input as Record | undefined if (selector.branch === 'default') { const defaultCase = input?.default as { portId?: string } | undefined if (!defaultCase?.portId) throw new Error(`No default branch on condition node '${node.name}' (${node.id})`) return defaultCase.portId } const cases = input?.cases as Array<{ portId?: string }> | undefined const portId = cases?.[selector.branch]?.portId if (!portId) throw new Error(`No branch ${selector.branch} on condition node '${node.name}' (${node.id})`) return portId } export function resolveTargetPort(node: WorkflowNode): string { const port = node.ports?.find(port => port.dir === 'in') if (!port) throw new Error(`No input port on node '${node.name}' (${node.id})`) return port.id }