Loop Engine

Packages

@loop-engine/runtime

@loop-engine/runtime is the execution layer that mutates loop state and emits lifecycle events.

Install

1npm install @loop-engine/runtime

Engine construction

1createLoopEngine(options: LoopEngineOptions): LoopEngine

LoopEngineOptions:

1interface LoopEngineOptions {
2 registry: LoopRegistry
3 store: LoopStore
4 eventBus?: EventBus
5 guardEvaluator?: GuardEvaluator
6 clock?: () => string
7}

Core methods

1start(options: StartOptions): Promise<LoopInstance>
2transition(options: TransitionOptions): Promise<TransitionResult>
3getState(aggregateId: AggregateId): Promise<LoopInstance | null>
4getHistory(aggregateId: AggregateId): Promise<TransitionRecord[]>
5listOpen(loopId: string, orgId: string): Promise<LoopInstance[]>
6registerSideEffectHandler(sideEffectId: string, handler: SideEffectHandler): void

Transition result statuses from source:

  • executed
  • guard_failed
  • rejected
  • pending_approval
1const result = await engine.transition({
2 aggregateId,
3 transitionId: transitionId("approve"),
4 actor: { type: "human", id: "manager@acme.com" },
5 evidence: { approved: true }
6})
7 
8if (result.status === "guard_failed") {
9 console.log(result.guardFailures)
10}

Store and bus interfaces

1interface LoopStore {
2 getInstance(aggregateId: AggregateId): Promise<LoopInstance | null>
3 saveInstance(instance: LoopInstance): Promise<void>
4 getTransitionHistory(aggregateId: AggregateId): Promise<TransitionRecord[]>
5 saveTransitionRecord(record: TransitionRecord): Promise<void>
6 listOpenInstances(loopId: LoopId, orgId: string): Promise<LoopInstance[]>
7}
8 
9interface EventBus {
10 emit(event: LoopEvent): Promise<void>
11 subscribe(handler: (event: LoopEvent) => Promise<void>): () => void
12}

Use @loop-engine/adapter-memory in development and @loop-engine/adapter-postgres for a production persistence target.