dispatcher-handlers
v0.1.6
Published
Shared handler contracts for frontend and backend.
Downloads
817
Readme
dispatcher-handlers
Zdieľaná TypeScript knižnica pre workflow handlery použiteľné na frontende aj backende.
Knižnica obsahuje:
- spoločné DTO typy pre handlery
HandlerRegistry, ktorý drží inštancie handlerov a routuje DTO podľatype- implementácie handlerov pre
control,log,logical,loop,rest,storage - podporu pre smart data placeholdery ako
@user.id
Inštalácia a build
npm install
npm run typecheck
npm run buildPublic API sa exportuje z root balíka:
import {
HandlerRegistry,
HandlerTypes,
type ControlProps,
type RestApiProps,
type LogProps,
} from "dispatcher-handlers";Základný koncept
Každý handler dostane DTO v tvare:
type HandlerRequestDto<T> = {
id: string;
timeout?: number;
handlerId: string;
type: HandlerType;
input: Record<string, any>;
data: T;
nextLines: string[];
currentLine?: string;
name?: string;
date?: Date;
};Kde:
idje identifikátor workflow runu alebo requestuhandlerIdje identifikátor konkrétneho handler nodetypeurčuje, ktorý handler sa má spustiťinputsú workflow premenné a runtime kontextdatasú dáta konkrétneho handleranextLinessú možné ďalšie workflow vetvy
Odpoveď handlera vracia rovnaký základ plus data a nextLine:
type HandlerResponseDto<R> = {
id: string;
handlerId: string;
type: HandlerType;
data: R;
nextLine: string;
currentLine?: string;
name?: string;
date?: Date;
};DTO aliasy
Pre každý handler existujú aliasy v dto/index.ts:
ControlProps,ControlResponseLogProps,LogResponseLogicalProps,LogicalResponseLoopProps,LoopResponseRestApiProps,RestApiResponseVirtualStorageProps,VirtualStorageResponse
To znamená, že v aplikačnom kóde zvyčajne nemusíš pracovať s generikami, ale s konkrétnym aliasom.
Handler types
Momentálne definované handler typy sú:
HandlerTypes.CONTROL;
HandlerTypes.LOG;
HandlerTypes.LOGICAL;
HandlerTypes.LOOP;
HandlerTypes.REST;
HandlerTypes.STORAGE;
HandlerTypes.WORKFLOW;HandlerRegistry aktuálne vytvára a obsluhuje tieto implementované handlery:
controlloglogicalloopreststorage
HandlerRegistry
HandlerRegistry je hlavný entry point. Drží dlhšie žijúce inštancie handlerov a podľa dto.type spustí správny handler.
To je dôležité hlavne pre:
ControlHandler, ktorý drží otvorené MQTT spojenieLogHandler, ktorý drží Redis client
Inicializácia
import { HandlerRegistry } from "dispatcher-handlers";
const registry = new HandlerRegistry({
control: {
brokerUrl: "mqtt://localhost:1883",
workflowEngineInstanceId: "engine-1",
responseTimeout: 30_000,
},
log: {
redisOptions: {
url: "redis://localhost:6379",
},
streamKey: "workflow:logs",
maxMessages: 1000,
},
storage: {
baseUrl: "http://localhost:3000/storage",
},
});Spustenie DTO
const response = await registry.execute({
id: "run-1",
handlerId: "rest-1",
type: "rest",
input: {
token: "secret-token",
userId: 42,
},
data: {
method: "GET",
type: "application/json",
url: "https://example.com/users/:userId",
header: {
Authorization: "Bearer @token",
},
payload: "",
queries: {},
params: {
userId: "@userId",
},
},
nextLines: ["next-node"],
});Registry pred spustením handlera automaticky spraví normalizáciu smart data cez Handler.formatSmartData().
Uvoľnenie zdrojov
Ak aplikáciu vypínaš, zavolaj:
await registry.dispose();To korektne zavrie dlhšie žijúce klienty, napríklad MQTT a Redis.
Smart data
Ak je payload.data stringified JSON alebo stringified hodnota, registry vie nahradiť placeholdery z input.
Používa sa symbol:
@Príklady placeholderov:
@user.id@session.token@items[0].name
Príklad:
const dto = {
input: {
user: {
id: 15,
name: "John",
},
},
data: '{"userId":"@user.id","name":"@user.name"}',
};Po spracovaní vznikne:
{
userId: 15,
name: "John",
}Ak reference v input neexistuje alebo výsledok nie je valid JSON, vyhodí sa chyba.
Príklady DTO
REST DTO
const restDto = {
id: "run-1",
handlerId: "rest-1",
type: "rest",
input: {
token: "secret-token",
},
data: {
method: "POST",
type: "application/json",
url: "https://example.com/items",
header: {
Authorization: "Bearer @token",
},
payload: '{"name":"Example"}',
queries: {},
params: {},
},
nextLines: ["after-rest"],
};Logical DTO
const logicalDto = {
id: "run-1",
handlerId: "logical-1",
type: "logical",
input: {
age: 20,
score: 95,
},
data: [
{
outputLineUid: "adult-branch",
conditions: {
operator: "&&",
conditions: [
{
if: "@age",
operator: ">=",
value: "18",
},
{
if: "@score",
operator: ">=",
value: "90",
},
],
},
},
],
nextLines: ["default-branch"],
};Loop DTO
const loopDto = {
id: "run-1",
handlerId: "loop-1",
type: "loop",
input: {
users: [
{ id: 1, active: true, name: "John" },
{ id: 2, active: false, name: "Jane" },
],
},
data: [
{
type: "filter",
from: "users",
where: {
if: "@item.active",
operator: "==",
value: "true",
},
},
{
type: "map",
from: "result",
mapper: {
id: "@item.id",
username: "@item.name",
},
},
],
nextLines: ["after-loop"],
};Control DTO
const controlDto = {
id: "run-1",
handlerId: "control-1",
type: "control",
input: {},
data: {
devices: [
{
id: "device-1",
os: "android",
resolution: [1080, 2400],
},
],
instructions: [
{
type: "openUrl",
url: "https://example.com",
},
],
},
nextLines: ["after-control"],
};Log DTO
const logDto = {
id: "run-1",
handlerId: "log-1",
type: "log",
input: {
userId: 42,
},
data: {
type: "INFO",
message: "User flow started",
},
nextLines: ["after-log"],
};Storage DTO
const storageDto = {
id: "run-1",
handlerId: "storage-1",
type: "storage",
input: {},
data: {
id: "session",
action: "SET",
data: {
token: "abc",
refreshToken: "def",
},
},
nextLines: ["after-storage"],
};Čo vracajú jednotlivé handlery
control: MQTT execution summary pre všetky zariadenialog: Redis stream entry id a zapísané fieldslogical: výsledok vyhodnotenia podmienok a zvolenýoutputLineUidloop: finálny pipelineresulta medzikrokyrest: HTTP response metadata, headers a bodystorage: HTTP response metadata, headers a body zo storage API
Poznámky
workflowDTO typ je v type systéme pripravený, ale nie je ešte implementovaný vHandlerRegistry.ControlHandleraLogHandlersú navrhnuté ako long-lived inštancie.HandlerRegistry.execute()vie pracovať aj so stringifieddata, ak obsahuje smart placeholdery.
