export type BreakConfig = { condition: string; }; // return export type ReturnConfig = { data: string; }; // wait export type WaitConfig = { condition: string; }; // throw export type ThrowConfig = { error: string; }; export enum WAIT_NUM { WAIT_UNSPECIFIED = 0, WAIT_ALL = 1, WAIT_NONE = 2 } export enum WAIT_STR { WAIT_UNSPECIFIED = 'WAIT_UNSPECIFIED', WAIT_ALL = 'WAIT_ALL', WAIT_NONE = 'WAIT_NONE' } export type ParallelConfig = { wait: WAIT_NUM | WAIT_STR; poolSize?: number; static?: { paths: Record; }; dynamic?: { variables: { item: string; }; paths: string; blocks?: BaseBlock[]; }; }; // conditional type Condition = { condition: string; blocks?: BaseBlock[]; }; export type ConditionalConfig = { if?: Condition; elseIf?: Condition[]; else?: { blocks?: BaseBlock[] }; }; // loop export enum LOOP_TYPE { UNSPECIFIED = 'TYPE_UNSPECIFIED', FOR = 'TYPE_FOR', FOREACH = 'TYPE_FOREACH', WHILE = 'TYPE_WHILE' } export type LoopConfig = { variables: { index: string; item: string; }; range: string; blocks?: BaseBlock[]; type: LOOP_TYPE; }; // try catch export type TryCatchConfig = { variables: { error: string; }; try?: { blocks?: BaseBlock[] }; catch?: { blocks?: BaseBlock[] }; finally?: { blocks?: BaseBlock[] }; }; // variables export enum VariableType { UNSPECIFIED = 'TYPE_UNSPECIFIED', SIMPLE = 'TYPE_SIMPLE', ADVANCED = 'TYPE_ADVANCED' } export enum VariableMode { UNSPECIFIED = 'MODE_UNSPECIFIED', READ = 'MODE_READ', READWRITE = 'MODE_READWRITE' } type VariableConfig = { value: string; key: string; type: VariableType; mode: VariableMode; }; export type VariablesConfig = { items: Array; }; // send export type SendConfig = { message: string; }; // stream export type StreamConfig = { variables: { item: string; }; trigger?: BaseBlock; process?: { blocks?: BaseBlock[] }; options?: { disable_auto_send: boolean; }; }; // step type StepPluginType = string; // This will be something like "python" | "bigquery" ... export type StepConfig = { integration?: string; } & { [plugin in StepPluginType]?: unknown; }; export type BaseBlock = { name: string; // only one of the following configs will be defined in a valid block break?: BreakConfig; return?: ReturnConfig; wait?: WaitConfig; throw?: ThrowConfig; parallel?: ParallelConfig; conditional?: ConditionalConfig; loop?: LoopConfig; tryCatch?: TryCatchConfig; step?: StepConfig; stream?: StreamConfig; send?: SendConfig; variables?: VariablesConfig; }; const ALL_BLOCK_TYPES = [ 'break', 'return', 'wait', 'throw', 'parallel', 'conditional', 'loop', 'tryCatch', 'step', 'variables', 'send', 'stream' ] as const; export const BlockType = { CONDITION: 'CONDITION', LOOP: 'LOOP', PARALLEL: 'PARALLEL', TRY_CATCH: 'TRY_CATCH', VARIABLES: 'VARIABLES', RETURN: 'RETURN', BREAK: 'BREAK', WAIT: 'WAIT', THROW: 'THROW', STEP: 'STEP', SEND: 'SEND', STREAM: 'STREAM' } as const; type BlockType = (typeof BlockType)[keyof typeof BlockType]; export type GenericBlock = { type: BlockType; config: | StepConfig | ConditionalConfig | LoopConfig | ParallelConfig | TryCatchConfig | VariableConfig | ReturnConfig | BreakConfig | WaitConfig | ThrowConfig | SendConfig | StreamConfig; }; export type StepBlock = { type: 'STEP'; config: StepConfig; }; export type ControlBlock = { type: Exclude; config: | ConditionalConfig | LoopConfig | ParallelConfig | TryCatchConfig | VariableConfig | ReturnConfig | BreakConfig | WaitConfig | ThrowConfig | SendConfig | StreamConfig; }; function getBlockType(type: (typeof ALL_BLOCK_TYPES)[number]): BlockType { switch (type) { case 'break': return BlockType.BREAK; case 'return': return BlockType.RETURN; case 'wait': return BlockType.WAIT; case 'throw': return BlockType.THROW; case 'parallel': return BlockType.PARALLEL; case 'conditional': return BlockType.CONDITION; case 'loop': return BlockType.LOOP; case 'tryCatch': return BlockType.TRY_CATCH; case 'variables': return BlockType.VARIABLES; case 'send': return BlockType.SEND; case 'stream': return BlockType.STREAM; case 'step': return BlockType.STEP; default: { const exhaustiveCheck: never = type; throw new Error(`Unhandled block type: ${exhaustiveCheck}`); } } } export function convertBlock(backendBlock: BaseBlock): GenericBlock | null { for (const blockType of ALL_BLOCK_TYPES) { if (blockType in backendBlock) { const config = backendBlock[blockType]; if (config != null) { return { type: getBlockType(blockType), config }; } } } return null; } export function isStepBlock(block: GenericBlock): block is StepBlock { return block.type === BlockType.STEP; } export function isControlBlock(block: GenericBlock): block is ControlBlock { return !isStepBlock(block); } export function getPluginType(block: GenericBlock): StepPluginType | null { if (isStepBlock(block)) { return block.config.integration ?? null; } return null; }