NestflowJS LogoNestflowJS

Adapters

Adapters bridge your infrastructure and the orchestration engine. They call OrchestratorService.transit() in a loop and react to each result.

TransitResult

Every call to orchestrator.transit() returns a TransitResult — a discriminated union that tells the caller what happened and what to do next.

Type Definition

import type { TransitResult, IWorkflowEvent } from 'nestflow-js/core';

type TransitResult =
  | { status: 'final'; state: string | number }
  | { status: 'idle'; state: string | number; timeout?: Duration }
  | { status: 'continued'; nextEvent: IWorkflowEvent }
  | { status: 'no_transition'; state: string | number; timeout?: Duration };
StatusMeaningWhat to do
finalEntity reached a terminal state. Workflow is complete.Return the result — nothing more to do.
idleEntity is in an idle state, waiting for external input.Wait for a callback or poll a queue. Optional timeout hints how long.
continuedA follow-up transition was found automatically.Feed nextEvent back into transit() to continue processing.
no_transitionNo unambiguous auto-transition from the current state.Wait for an explicit event from an external system.

IWorkflowEvent

The event envelope consumed by orchestrator.transit():

interface IWorkflowEvent<T = any> {
  event: string;           // Event name that triggers a transition
  urn: string | number;    // Unique identifier for the entity
  payload?: T | object | string; // Optional event data
  attempt: number;         // Retry attempt number (starts at 0)
}

Usage Example

import { OrchestratorService } from 'nestflow-js/core';
import type { TransitResult, IWorkflowEvent } from 'nestflow-js/core';

@Injectable()
export class MyService {
  constructor(private orchestrator: OrchestratorService) {}

  async processEvent(event: IWorkflowEvent) {
    const result: TransitResult = await this.orchestrator.transit(event);

    switch (result.status) {
      case 'final':
        console.log('Completed in state:', result.state);
        break;
      case 'idle':
        console.log('Idle at state:', result.state);
        break;
      case 'continued':
        // Feed it back to continue the workflow
        await this.processEvent(result.nextEvent);
        break;
      case 'no_transition':
        console.log('Waiting at state:', result.state);
        break;
    }
  }
}

BaseWorkflowAdapter

The abstract class that encapsulates the orchestration loop. It calls transit() and dispatches each TransitResult variant to a dedicated handler method:

import { BaseWorkflowAdapter } from 'nestflow-js/adapter';

// TContext = your runtime context (e.g. IDurableContext, Express Request)
// TResult  = the value your adapter returns when the workflow completes
abstract class BaseWorkflowAdapter<TContext, TResult> {
  protected runWorkflowLoop(initialEvent, ctx): Promise<TResult>;

  // Override these in your concrete adapter:
  protected abstract executeTransit(event, iteration, ctx): Promise<TransitResult>;
  protected abstract onFinal(result, event, ctx): TResult;
  protected abstract onIdle(result, event, iteration, ctx): Promise<IWorkflowEvent>;
  protected abstract onContinued(result, iteration, ctx): Promise<IWorkflowEvent>;
  protected abstract onNoTransition(result, event, iteration, ctx): Promise<IWorkflowEvent>;
}

Each handler receives a narrowed result type (e.g. Extract<TransitResult, { status: 'idle' }>) for full type safety.

Creating Custom Adapters

Use OrchestratorService directly for simple integrations, or extend BaseWorkflowAdapter for the full loop pattern.

HTTP Adapter Example

import { Controller, Post, Body } from '@nestjs/common';
import { OrchestratorService } from 'nestflow-js/core';
import type { IWorkflowEvent } from 'nestflow-js/core';

@Controller('workflow')
export class WorkflowController {
  constructor(private orchestrator: OrchestratorService) {}

  @Post('events')
  async handleEvent(@Body() event: IWorkflowEvent) {
    await this.orchestrator.transit(event);
    return { status: 'processed' };
  }
}

EventBridge Adapter Example

import { EventBridgeHandler } from 'aws-lambda';
import { OrchestratorService } from 'nestflow-js/core';

export const handler: EventBridgeHandler<string, any, void> = async (event) => {
  const app = await getApp();
  const orchestrator = app.get(OrchestratorService);

  const workflowEvent = {
    event: event['detail-type'],
    urn: event.detail.entityId,
    payload: event.detail,
    attempt: 0,
  };

  await orchestrator.transit(workflowEvent);
};