# Engine SDK

Das Engine SDK stellt Typen und Schnittstellen bereit, um Extensions für die Engine zu entwickeln.

## Verwendung des SDKs

Das SDK kann über npm bezogen werden:

```sh
npm i --save @5minds/processcube_engine_sdk
```

Beispiel:

```ts
import { Engine, EngineEvent, OnLoad } from '@5minds/processcube_engine_sdk';

export const onLoad: OnLoad = (engine: Engine) => {
  engine.registerEventMiddleware(onEngineEvent);
};

function onEngineEvent(event: EngineEvent): Promise<void> {
  return Promise.resolve();
}
```

## Extensions in die Engine einbinden

Standardmäßig werden Extensions aus dem Ordner `${HOME}/.processcube/engine/extensions` geladen. Der Pfad lässt sich mit dem Startup-Parameter
`--extensionsDir` ändern.

Sowohl beim Start über die CLI:

```sh
processcube-engine --extensionsDir '/my/custom/extensions/dir'
```

Als auch beim Start als embedded Software:

```ts
await Engine.launch({
  extensionsDir: '/my/custom/extensions/dir',
});
```

## Aufbau einer Extension

Jede zu ladende Extension muss in einem eigenen Unterordner von `extensionsDir` liegen und mindestens eine package.json und eine nach JavaScript
transpilierte Einstiegspunkt-Datei enthalten, die in der package.json als `main` angegeben ist.

```sh
tree -L 2 ${HOME}/.processcube/engine/extensions
├── extension01
│   ├── index.js
│   └── package.json
└── extension02
    ├── index.js
    └── package.json
```

Jede Extension muss mindestens eine eigene package.json mit `name`, `version` und `main` enthalten.

```json
{
  "name": "extension01",
  "version": "1.0.0",
  "main": "index.js",
  "dependencies": {
    "@5minds/processcube_engine_sdk": "^3.3.0"
  }
}
```

`main` muss auf eine gültige JavaScript-Datei zeigen, in welcher die Extension gehostet wird.

In der `main`-Datei können Extensions eine onLoad-Funktion exportieren, die von der Engine beim Laden mit einem
[Engine-Objekt](#Interaktion-mit-der-Engine) als Parameter aufgerufen wird. In diesem Objekt finden sich alle Engine Funktionen,
die von einer Extension genutzt werden können.

```ts
export const onLoad: OnLoad = (engine: Engine) => {
  engine.registerEventMiddleware(onEngineEvent);
};
```

## Interaktion mit der Engine

Der `Engine` Typ stellt Schnittstellen zur Interaktion mit der Engine bereit.

### registerEventMiddleware

`registerEventMiddleware` erlaubt es einer Extension sich auf Log Events der Engine zu subscriben.

Der hier angegebene Callback wird dann bei jedem eingehenden Log Event ausgeführt.

```ts
import { Engine, EngineEvent, OnLoad } from '@5minds/processcube_engine_sdk';

export const onLoad: OnLoad = (engine: Engine): void => {
  // Die Funktion `onEngineEvent` wird als Event-Middleware registriert
  engine.registerEventMiddleware(onEngineEvent);
};

// Gibt den Typen jedes empfangenen Events auf der Konsole aus
function onEngineEvent(event: EngineEvent): void {
  console.log(`Received event ${event.eventType}`);
}
```

#### EngineActions

Die Engine erlaubt mittels EngineActions ein Eingreifen in die Prozessausführung.
Eine Middleware kann eine, keine oder mehrere EngineActions zurückgeben, die dann von der Engine nacheinander ausgeführt werden,
bevor die Prozessausführung fortgesetzt wird.

Eine EngineAction ist ein Datenobjekt, dass mindestens eine Id enthält, die die Art der EngineAction festlegt und weitere EngineAction-spezifische Properties,
die für die Ausführung der EngineAction benötigt werden.

```ts
import { Engine, EngineEvent, LogEventType, OnLoad } from '@5minds/processcube_engine_sdk';

export const onLoad: OnLoad = (engine: Engine): void => {
  // Die Funktion `onEngineEvent` wird als Event-Middleware registriert
  engine.registerEventMiddleware(onEngineEvent);
};

// Gibt den Typen jedes empfangenen Events auf der Konsole aus
function onEngineEvent(event: EngineEvent): void {
  console.log(`Received event ${event.eventType}`);

  if (event.eventType === LogEventType.OnFlowNodeExited) {
    // Gibt die EngineAction 'ModifyTokenPayload' zurück
    return {
      id: 'ModifyTokenPayload',
      tokenPayload: { result: 'token was modified' },
    };
  }
}
```

Folgende EngineActions werden derzeit unterstützt:

##### ModifyTokenPayload Action

Die `ModifyTokenPayload` Action kann verwendet werden um den Payload des aktuellen Tokens zu verändern.
Daher kann die `ModifyTokenPayload` Action nur verwendet werden, wenn das auslösende EngineEvent zu einer FlowNode gehört.
Solche Events fangen immer mit `OnFlowNode` an (bspw.: `OnFlowNodeEntered`).
Sollte eine `ModifyTokenPayload` Action für ein Event das nicht zu einer FlowNode gehört zurückgegeben wird,
wird die Action nicht ausgeführt und ein Fehler wird gelogt.

Eine `ModifyTokenPayload` Action besteht aus 2 Eigenschaften:

1. Die `id`, die immer `ModifyTokenPayload` entspricht
2. Die `tokenPayload`, der den payload des aktuellen Tokens der entsprechenden FlowNode ersetzt.

```ts
{
  id: 'ModifyTokenPayload',
  tokenPayload: {example: 'token payload'},
}
```

Werden mehrere `ModifyTokenPayload` Actions zurückgegeben, überschreibt der letzte TokenPayload immer die Vorherigen.

## Weiterführende Links

- [Engine](https://github.com//5minds/ProcessCube.Engine)
- [TS Client](https://github.com//5minds/ProcessCube.Engine.Client.ts)
