import type { CurrentStateExecutionRequest, HttpMethod, Items, NodeActivationContinuation, NodeActivationId, NodeExecutionRequest, NodeExecutionRequestHandler, NodeId, NodeInputsByPort, NodeOutputs, ParentExecutionRef, PersistedWorkflowTokenRegistryLike, ResumeContext, RunExecutionOptions, RunId, RunResult, WorkflowExecutionRepository, WebhookRunResult, WebhookTriggerMatcher, WebhookTriggerResolution, WorkflowDefinition, WorkflowId, LiveWorkflowRepository, WorkflowSnapshotResolver, } from "../types"; interface EngineTriggerRuntime { startTriggers(): Promise; stop(): Promise; syncWorkflowTriggersForActivation(workflowId: WorkflowId): Promise; createTriggerTestItems(args: { workflow: WorkflowDefinition; nodeId: NodeId }): Promise; } interface EngineRunStartService { runWorkflow( wf: WorkflowDefinition, startAt: NodeId, items: Items, parent?: ParentExecutionRef, executionOptions?: RunExecutionOptions, persistedStateOverrides?: Readonly<{ workflowSnapshot?: NonNullable>>["workflowSnapshot"]; mutableState?: NonNullable>>["mutableState"]; }>, ): Promise; runWorkflowFromState(request: CurrentStateExecutionRequest): Promise; } interface EngineRunContinuationService { markNodeRunning(args: { runId: RunId; activationId: NodeActivationId; nodeId: NodeId; inputsByPort: NodeInputsByPort; }): Promise; resumeFromNodeResult(args: { runId: RunId; activationId: NodeActivationId; nodeId: NodeId; outputs: NodeOutputs; }): Promise; resumeFromNodeError(args: { runId: RunId; activationId: NodeActivationId; nodeId: NodeId; error: Error; }): Promise; resumeFromStepResult(args: { runId: RunId; activationId: NodeActivationId; nodeId: NodeId; outputs: NodeOutputs; }): Promise; resumeFromStepError(args: { runId: RunId; activationId: NodeActivationId; nodeId: NodeId; error: Error; }): Promise; waitForCompletion(runId: RunId): Promise>; waitForWebhookResponse(runId: RunId): Promise; resumeRun(args: { runId: RunId; taskId: string; resumeContext: ResumeContext }): Promise; } interface EngineNodeExecutionRequestHandler { handleNodeExecutionRequest(request: NodeExecutionRequest): Promise; } export interface EngineFacadeDeps { liveWorkflowRepository: LiveWorkflowRepository; tokenRegistry: PersistedWorkflowTokenRegistryLike; webhookTriggerMatcher: WebhookTriggerMatcher; workflowSnapshotResolver: WorkflowSnapshotResolver; triggerRuntime: EngineTriggerRuntime; runStartService: EngineRunStartService; runContinuationService: EngineRunContinuationService; nodeExecutionRequestHandler: EngineNodeExecutionRequestHandler; } export class Engine implements NodeActivationContinuation, NodeExecutionRequestHandler { constructor(private readonly deps: EngineFacadeDeps) {} loadWorkflows(workflows: ReadonlyArray): void { this.deps.tokenRegistry.registerFromWorkflows?.(workflows); this.deps.liveWorkflowRepository.setWorkflows(workflows); this.deps.webhookTriggerMatcher.onEngineWorkflowsLoaded?.(); } getTokenRegistry(): EngineFacadeDeps["tokenRegistry"] { return this.deps.tokenRegistry; } resolveWorkflowSnapshot(args: { workflowId: WorkflowId; workflowSnapshot?: NonNullable>>["workflowSnapshot"]; }): WorkflowDefinition | undefined { return this.deps.workflowSnapshotResolver.resolve(args); } async startTriggers(): Promise { return await this.deps.triggerRuntime.startTriggers(); } async syncWorkflowTriggersForActivation(workflowId: WorkflowId): Promise { await this.deps.triggerRuntime.syncWorkflowTriggersForActivation(workflowId); this.deps.webhookTriggerMatcher.reloadWebhookRoutes?.(); } async start(workflows: WorkflowDefinition[]): Promise { await this.stop(); this.loadWorkflows(workflows); await this.startTriggers(); } async stop(): Promise { await this.deps.triggerRuntime.stop(); this.deps.webhookTriggerMatcher.onEngineStopped?.(); } resolveWebhookTrigger(args: { endpointPath: string; method: HttpMethod }): WebhookTriggerResolution { const entry = this.deps.webhookTriggerMatcher.lookup(args.endpointPath); if (!entry) { return { status: "notFound" }; } if (!entry.methods.includes(args.method)) { return { status: "methodNotAllowed", match: entry }; } return { status: "ok", match: entry }; } async createTriggerTestItems(args: { workflow: WorkflowDefinition; nodeId: NodeId }): Promise { return await this.deps.triggerRuntime.createTriggerTestItems(args); } async runWorkflow( wf: WorkflowDefinition, startAt: NodeId, items: Items, parent?: ParentExecutionRef, executionOptions?: RunExecutionOptions, persistedStateOverrides?: Readonly<{ workflowSnapshot?: NonNullable>>["workflowSnapshot"]; mutableState?: NonNullable>>["mutableState"]; }>, ): Promise { return await this.deps.runStartService.runWorkflow( wf, startAt, items, parent, executionOptions, persistedStateOverrides, ); } async runWorkflowFromState(request: CurrentStateExecutionRequest): Promise { return await this.deps.runStartService.runWorkflowFromState(request); } async markNodeRunning(args: { runId: RunId; activationId: NodeActivationId; nodeId: NodeId; inputsByPort: NodeInputsByPort; }): Promise { return await this.deps.runContinuationService.markNodeRunning(args); } async resumeFromNodeResult(args: { runId: RunId; activationId: NodeActivationId; nodeId: NodeId; outputs: NodeOutputs; }): Promise { return await this.deps.runContinuationService.resumeFromNodeResult(args); } async resumeFromNodeError(args: { runId: RunId; activationId: NodeActivationId; nodeId: NodeId; error: Error; }): Promise { return await this.deps.runContinuationService.resumeFromNodeError(args); } async resumeFromStepResult(args: { runId: RunId; activationId: NodeActivationId; nodeId: NodeId; outputs: NodeOutputs; }): Promise { return await this.deps.runContinuationService.resumeFromStepResult(args); } async resumeFromStepError(args: { runId: RunId; activationId: NodeActivationId; nodeId: NodeId; error: Error; }): Promise { return await this.deps.runContinuationService.resumeFromStepError(args); } async waitForCompletion(runId: RunId): Promise> { return await this.deps.runContinuationService.waitForCompletion(runId); } async waitForWebhookResponse(runId: RunId): Promise { return await this.deps.runContinuationService.waitForWebhookResponse(runId); } async resumeRun(args: { runId: RunId; taskId: string; resumeContext: ResumeContext }): Promise { return await this.deps.runContinuationService.resumeRun(args); } async handleNodeExecutionRequest(request: NodeExecutionRequest): Promise { await this.deps.nodeExecutionRequestHandler.handleNodeExecutionRequest(request); } }